[Graph] Make edge selection work (#127456)

* 🐛 Fix edge selection + empty data message

* 🐛 Fix issue and make it owkr for single selection

*  Fix tests

* 🐛 Fix toggle edge selection

*  Fix tests

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Marco Liberati 2022-03-16 11:06:16 +01:00 committed by GitHub
parent 574ba8de08
commit b6fc484e5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 12 deletions

View file

@ -126,7 +126,7 @@ const ControlPanelComponent = ({
{control === 'editLabel' && selectedNode && (
<SelectedNodeEditor workspace={workspace} selectedNode={selectedNode} />
)}
{control === 'mergeTerms' && mergeCandidates.length > 0 && (
{control === 'mergeTerms' && (
<MergeCandidates
workspace={workspace}
mergeCandidates={mergeCandidates}

View file

@ -7,7 +7,7 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiToolTip } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { ControlType, TermIntersect, Workspace } from '../../types';
import { VennDiagram } from '../venn_diagram';
@ -49,6 +49,15 @@ export const MergeCandidates = ({
defaultMessage: 'Link summary',
})}
</div>
{mergeCandidates.length === 0 && (
<EuiFlexGroup alignItems="center" style={{ minHeight: 101 }}>
<EuiFlexItem component="span">
{i18n.translate('xpack.graph.sidebar.linkSummary.noData', {
defaultMessage: 'No terms intersection found for the link selection.',
})}
</EuiFlexItem>
</EuiFlexGroup>
)}
{mergeCandidates.map((mc) => {
const mergeTerm1ToTerm2ButtonMsg = i18n.translate(
'xpack.graph.sidebar.linkSummary.mergeTerm1ToTerm2ButtonTooltip',

View file

@ -110,6 +110,10 @@ describe('graph_visualization', () => {
return !node.isSelected;
}),
getAllIntersections: jest.fn(),
removeEdgeFromSelection: jest.fn(),
addEdgeToSelection: jest.fn(),
getEdgeSelection: jest.fn().mockImplementation(() => []),
clearEdgeSelection: jest.fn(),
} as unknown as jest.Mocked<Workspace>;
beforeEach(() => {
@ -207,5 +211,6 @@ describe('graph_visualization', () => {
expect(workspace.getAllIntersections).toHaveBeenCalled();
expect(edges[0].topSrc).toEqual(workspace.getAllIntersections.mock.calls[0][1][0]);
expect(edges[0].topTarget).toEqual(workspace.getAllIntersections.mock.calls[0][1][1]);
expect(workspace.removeEdgeFromSelection).toHaveBeenCalled();
});
});

View file

@ -37,6 +37,13 @@ function registerZooming(element: SVGSVGElement) {
);
}
function makeEdgeId(edge: WorkspaceEdge) {
return `${makeNodeId(edge.source.data.field, edge.source.data.term)}-${makeNodeId(
edge.target.data.field,
edge.target.data.term
)}`;
}
export function GraphVisualization({
workspace,
selectSelected,
@ -68,8 +75,23 @@ export function GraphVisualization({
onSetControl('mergeTerms');
};
const edgeClick = (edge: WorkspaceEdge) =>
workspace.getAllIntersections(handleMergeCandidatesCallback, [edge.topSrc, edge.topTarget]);
const edgeClick = (edge: WorkspaceEdge) => {
// no multiple selection for now
const currentSelection = workspace.getEdgeSelection();
if (currentSelection.length && currentSelection[0] !== edge) {
workspace.clearEdgeSelection();
}
if (!edge.isSelected) {
workspace.addEdgeToSelection(edge);
} else {
workspace.removeEdgeFromSelection(edge);
}
onSetControl('edgeSelection');
if (edge.isSelected) {
workspace.getAllIntersections(handleMergeCandidatesCallback, [edge.topSrc, edge.topTarget]);
}
};
return (
<svg
@ -90,13 +112,7 @@ export function GraphVisualization({
<g>
{workspace.edges &&
workspace.edges.map((edge) => (
<g
key={`${makeNodeId(edge.source.data.field, edge.source.data.term)}-${makeNodeId(
edge.target.data.field,
edge.target.data.term
)}`}
className="gphEdge--wrapper"
>
<g key={makeEdgeId(edge)} className="gphEdge--wrapper">
{/* Draw two edges: a thicker one for better click handling and the one to show the user */}
<line
x1={edge.topSrc.kx}

View file

@ -113,6 +113,7 @@ function GraphWorkspace(options) {
this.undoLog = [];
this.redoLog = [];
this.selectedNodes = [];
this.selectedEdges = [];
if (!options) {
this.options = {};
@ -228,6 +229,25 @@ function GraphWorkspace(options) {
}
};
this.addEdgeToSelection = function (edge) {
edge.isSelected = true;
self.selectedEdges.push(edge);
};
this.removeEdgeFromSelection = function (edge) {
edge.isSelected = false;
self.selectedEdges = self.selectedEdges.filter((e) => e !== edge);
};
this.clearEdgeSelection = function () {
for (const edge of self.selectedEdges) {
edge.isSelected = false;
}
self.selectedEdges = [];
};
this.getEdgeSelection = () => [...self.selectedEdges];
this.deleteSelection = function () {
let allAndGrouped = self.returnUnpackedGroupeds(self.selectedNodes);
@ -382,6 +402,7 @@ function GraphWorkspace(options) {
this.edgesMap = {};
this.blocklistedNodes = [];
this.selectedNodes = [];
this.selectedEdges = [];
this.lastResponse = null;
};

View file

@ -146,6 +146,11 @@ export interface Workspace {
runLayout(): void;
stopLayout(): void;
addEdgeToSelection(edge: WorkspaceEdge): void;
removeEdgeFromSelection(edge: WorkspaceEdge): void;
clearEdgeSelection(): void;
getEdgeSelection(): WorkspaceEdge[];
}
export type ExploreRequest = any;
@ -173,4 +178,10 @@ export type WorkspaceOptions = Partial<{
exploreControls: AdvancedSettings;
}>;
export type ControlType = 'style' | 'drillDowns' | 'editLabel' | 'mergeTerms' | 'none';
export type ControlType =
| 'style'
| 'drillDowns'
| 'editLabel'
| 'mergeTerms'
| 'none'
| 'edgeSelection';