mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[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:
parent
574ba8de08
commit
b6fc484e5c
6 changed files with 74 additions and 12 deletions
|
@ -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}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue