diff --git a/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc b/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc index dc4025b883d..babbbd913fb 100644 --- a/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc +++ b/docs/modules/ROOT/pages/operations/on-canvas-operations.adoc @@ -32,4 +32,12 @@ image:modifying-node-label-example.png[width=600] == Creating On-Canvas Relationships Alt-clicking one node, release the alk key, and alt-clicking another node will create a relationship between the two - \ No newline at end of file + +== Editing the Relationshiop Type and Properties in Node Inspection Panel + +[NOTE] +==== +Make sure APOC plugin is enabled in Neo4J database: + +image:enable-apoc.png[width=600] +==== \ No newline at end of file diff --git a/e2e_tests/integration/node-inspection-panel.spec.ts b/e2e_tests/integration/node-inspection-panel.spec.ts deleted file mode 100644 index b8e4186f3b7..00000000000 --- a/e2e_tests/integration/node-inspection-panel.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Jiaqi Liu - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* global Cypress, cy, before */ - -describe('Node Inspection Panel rendering', () => { - before(function () { - cy.visit(Cypress.config('url')).title().should('include', 'Neo4j Browser') - cy.wait(3000) - cy.ensureConnection() - }) - - afterEach(() => { - cy.executeCommand('MATCH (n) DETACH DELETE n') - }) - - it('should display node/rel caption as panel title', () => { - cy.executeCommand(':clear') - cy.executeCommand(`CREATE (s:SourceNode {name: 'My Node'}) RETURN s`, { - parseSpecialCharSequences: false - }) - - cy.get(`[aria-label^="graph-node"]`) - .trigger('mouseover', { force: true }) - .trigger('mouseenter', { force: true }) - .get('[data-testid="viz-details-pane-title"]') - .contains('My Node') - }) - - it('details pane title should be editable', () => { - cy.executeCommand(':clear') - cy.executeCommand(`CREATE (s:SourceNode {name: 'My Node'}) RETURN s`, { - parseSpecialCharSequences: false - }) - - cy.get(`[aria-label^="graph-node"]`) - .trigger('mouseover', { force: true }) - .trigger('mouseenter', { force: true }) - .get('[data-testid="viz-details-pane-title"]') - .find('[contenteditable]') - .clear() - .type('New Title{enter}', { force: true }) - - cy.wait(1500) - - cy.get(`[aria-label^="graph-node"]`) - .first() - .trigger('mouseover', { force: true }) - .trigger('mouseenter', { force: true }) - .get('[data-testid="viz-details-pane-title"]') - .contains('New Title') - }) -}) diff --git a/e2e_tests/integration/node-inspectior-panel.spec.ts b/e2e_tests/integration/node-inspectior-panel.spec.ts new file mode 100644 index 00000000000..39284ca5123 --- /dev/null +++ b/e2e_tests/integration/node-inspectior-panel.spec.ts @@ -0,0 +1,137 @@ +/* + * Copyright Jiaqi Liu + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* global Cypress, cy, before */ + +describe('Node Inspection Panel rendering', () => { + before(function () { + cy.visit(Cypress.config('url')).title().should('include', 'Neo4j Browser') + cy.wait(3000) + cy.ensureConnection() + }) + + afterEach(() => { + cy.executeCommand('MATCH (n) DETACH DELETE n') + }) + + it('should display node/rel caption as panel title', () => { + cy.executeCommand(':clear') + cy.executeCommand(`CREATE (s:SourceNode {name: 'My Node'}) RETURN s`, { + parseSpecialCharSequences: false + }) + + cy.get(`[aria-label^="graph-node"]`) + .trigger('mouseover', { force: true }) + .trigger('mouseenter', { force: true }) + .get('[data-testid="viz-details-pane-title"]') + .contains('My Node') + }) + + it('details pane title should be editable and pressing enter does not insert a line break at the end of new title', () => { + cy.executeCommand(':clear') + cy.executeCommand(`CREATE (s:SourceNode {name: 'My Node'}) RETURN s`, { + parseSpecialCharSequences: false + }) + + cy.get(`[aria-label^="graph-node"]`) + .trigger('mouseover', { force: true }) + .trigger('mouseenter', { force: true }) + .get('[data-testid="viz-details-pane-title"]') + .find('[contenteditable]') + .clear() + .type('New Title{enter}', { force: true }) + + cy.wait(1500) + + cy.get(`[aria-label^="graph-node"]`) + .first() + .trigger('mouseover', { force: true }) + .trigger('mouseenter', { force: true }) + .get('[data-testid="viz-details-pane-title"]') + .contains('New Title') + .should(title => { + expect(title.text()).to.equal('New Title') + }) + }) + + it('can directly modify node label in node inspector panel and pressing enter does not insert a line break at the end of new label', () => { + cy.executeCommand(':clear') + cy.executeCommand(`CREATE (a:TestLabel {name: 'testNode'}) RETURN a`, { + parseSpecialCharSequences: false + }) + + cy.get(`[aria-label^="graph-node"]`) + .first() + .trigger('mouseover', { force: true }) + .trigger('mouseenter', { force: true }) + .trigger('click', { force: true }) + .get('[data-testid="styleable-node-label"]', { timeout: 5000 }) + .clear() + .type('New Label{enter}', { force: true }) + .wait(1500) + .get('[data-testid="styleable-node-label"]', { timeout: 5000 }) + .contains('New Label') + .should(label => { + expect(label.text()).to.equal('New Label') + }) + }) + + it('can directly modify relationship type in node inspector panel', () => { + cy.executeCommand(':clear') + cy.executeCommand( + 'CREATE (a:TestLabel)-[:CONNECTS]->(b:TestLabel) RETURN a, b' + ) + .wait(3000) + .get('.relationship', { timeout: 5000 }) + .trigger('click', { force: true }) + .get('[data-testid="styleable-rel-type"]', { timeout: 5000 }) + .first() + .clear() + .type('New Link Label{enter}', { force: true }) + .wait(1500) + .get('[data-testid="styleable-rel-type"]', { timeout: 5000 }) + .contains('New Link Label') + }) + + it('can directly modify properties table value and pressing enter does not insert a line break at the end of new value', () => { + cy.executeCommand(':clear') + cy.executeCommand(`CREATE (a:TestLabel {name: 'testNode'}) RETURN a`, { + parseSpecialCharSequences: false + }) + .wait(3000) + .get(`[aria-label^="graph-node"]`) + .first() + .trigger('mouseover', { force: true }) + .trigger('mouseenter', { force: true }) + .trigger('click', { force: true }) + .get('[data-testid="properties-table-name-value-cell"]', { + timeout: 5000 + }) + .clear() + .type('New Name{enter}', { force: true }) + .wait(1500) + .get('[data-testid="properties-table-name-value-cell"]', { + timeout: 5000 + }) + .contains('New Name') + .should(cellValue => { + expect(cellValue.text()).to.equal('New Name') + }) + }) +}) diff --git a/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableNodeLabel.tsx b/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableNodeLabel.tsx index 8b753785672..f066fc7d21a 100644 --- a/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableNodeLabel.tsx +++ b/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableNodeLabel.tsx @@ -57,6 +57,7 @@ export function StyleableNodeLabel({ return (
{ diff --git a/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableRelType.tsx b/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableRelType.tsx index 1e936ff2ed3..b44fd7a45bc 100644 --- a/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableRelType.tsx +++ b/src/browser/modules/Stream/CypherFrame/VisualizationView/PropertiesPanelContent/StyleableRelType.tsx @@ -50,17 +50,26 @@ export function StyleableRelType({ }) return (
- onGraphInteraction(REL_TYPE_UPDATE, { - relId: relId, - sourceNodeId: sourceNodeId, - targetNodeId: targetNodeId, - oldType: selectedRelType.relType, - newType: e.currentTarget.textContent - }) - } + onKeyDown={(event: any) => { + if (event.key == 'Enter') { + event.preventDefault() // prevent new line char on Enter (https://stackoverflow.com/a/60008550) + } + }} + onKeyUp={(event: any) => { + if (event.keyCode === 13) { + event.preventDefault() + onGraphInteraction(REL_TYPE_UPDATE, { + relId: relId, + sourceNodeId: sourceNodeId, + targetNodeId: targetNodeId, + oldType: selectedRelType.relType, + newType: event.currentTarget.textContent + }) + } + }} > { diff --git a/src/neo4j-arc/common/components/PropertiesTable/PropertiesTable.tsx b/src/neo4j-arc/common/components/PropertiesTable/PropertiesTable.tsx index 66b620723b2..9915dfa74d2 100644 --- a/src/neo4j-arc/common/components/PropertiesTable/PropertiesTable.tsx +++ b/src/neo4j-arc/common/components/PropertiesTable/PropertiesTable.tsx @@ -75,6 +75,7 @@ function ExpandableValue({ return (
{ diff --git a/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/DefaultDetailsPane.tsx b/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/DefaultDetailsPane.tsx index 1f32ea56679..15f2e2df234 100644 --- a/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/DefaultDetailsPane.tsx +++ b/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/DefaultDetailsPane.tsx @@ -123,6 +123,7 @@ export function DefaultDetailsPane({ }} graphStyle={graphStyle} onGraphInteraction={onGraphInteraction} + relId={vizItem.item.id} sourceNodeId={vizItem.item.source.id} targetNodeId={vizItem.item.target.id} /> diff --git a/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/RelType.tsx b/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/RelType.tsx index a62811e0523..e9576ca0c1d 100644 --- a/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/RelType.tsx +++ b/src/neo4j-arc/graph-visualization/GraphVisualizer/DefaultPanelContent/RelType.tsx @@ -30,6 +30,7 @@ export type RelTypeProps = { graphStyle: GraphStyleModel selectedRelType: { relType: string; propertyKeys: string[]; count?: number } onGraphInteraction?: GraphInteractionCallBack + relId?: string sourceNodeId?: string targetNodeId?: string } @@ -40,6 +41,7 @@ export function RelType({ selectedRelType, graphStyle, onGraphInteraction = () => undefined, + relId, sourceNodeId, targetNodeId }: RelTypeProps): JSX.Element { @@ -59,6 +61,7 @@ export function RelType({ if (event.keyCode === 13) { event.preventDefault() onGraphInteraction(REL_TYPE_UPDATE, { + relId: relId, sourceNodeId: sourceNodeId, targetNodeId: targetNodeId, oldType: selectedRelType.relType, diff --git a/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts b/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts index 9a87578e308..943f6327e3e 100644 --- a/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts +++ b/src/neo4j-arc/graph-visualization/GraphVisualizer/Graph/GraphEventHandlerModel.ts @@ -42,8 +42,8 @@ export type GraphInteraction = | 'NODE_UNPINNED' | 'NODE_DISMISSED' | typeof NODE_ON_CANVAS_CREATE - | typeof NODE_LABEL_UPDATE | typeof REL_ON_CANVAS_CREATE + | typeof NODE_LABEL_UPDATE | typeof REL_TYPE_UPDATE | typeof PROP_UPDATE | typeof DETAILS_PANE_TITLE_UPDATE diff --git a/src/neo4j-arc/package.json b/src/neo4j-arc/package.json index 91755065db5..55f261d3e53 100644 --- a/src/neo4j-arc/package.json +++ b/src/neo4j-arc/package.json @@ -1,6 +1,6 @@ { "name": "neo4j-devtools-arc", - "version": "0.0.79", + "version": "0.0.80", "main": "dist/neo4j-arc.js", "author": "Neo4j Inc.", "license": "GPL-3.0",