Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions redisinsight/ui/src/packages/redisgraph/src/Graph.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useEffect, useRef, useState, useMemo } from 'react'
import React, { useEffect, useRef, useState, useMemo } from 'react'
import * as d3 from 'd3'
import { executeRedisCommand } from 'redisinsight-plugin-sdk'
import {
EuiButtonIcon,
EuiToolTip,
EuiSwitch,
} from '@elastic/eui'
import Graphd3, { IGraphD3 } from './graphd3'
import { responseParser } from './parser'
Expand Down Expand Up @@ -49,6 +50,7 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
const [container, setContainer] = useState<IGraphD3>(null)
const [selectedEntity, setSelectedEntity] = useState<ISelectedEntityProps | null>(null)
const [start, setStart] = useState<boolean>(false)
const [showAutomaticEdges, setShowAutomaticEdges] = useState(true);

const parsedResponse = responseParser(props.data)
let nodeIds = new Set(parsedResponse.nodes.map(n => n.id))
Expand Down Expand Up @@ -135,7 +137,7 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target) && !edgeIds.has(e.id))
.map(e => {
newEdgeTypes[e.type] = (newEdgeTypes[e.type] + 1 || 1)
return ({ ...e, startNode: e.source, endNode: e.target })
return ({ ...e, startNode: e.source, endNode: e.target, fetchedAutomatically: true })
})

setGraphData({
Expand Down Expand Up @@ -250,6 +252,18 @@ export default function Graph(props: { graphKey: string, data: any[] }) {

return (
<div className="core-container" data-testid="query-graph-container">
<div className="automatic-edges-switch">
<EuiToolTip position="bottom" delay="long" content="Toggle visibility of automatically fetched relationships">
<EuiSwitch
label="All relationships"
checked={showAutomaticEdges}
onChange={() => {
container.toggleShowAutomaticEdges()
setShowAutomaticEdges(!showAutomaticEdges)
}}
/>
</EuiToolTip>
</div>
<div className="d3-info">
<div className="graph-legends">
{
Expand All @@ -259,14 +273,14 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
Object.keys(nodeLabels).map((item, i) => (
<div
className="box-node-label"
style={{backgroundColor: labelColors(item).color, color: labelColors(item).textColor}}
style={{ backgroundColor: labelColors(item).color, color: labelColors(item).textColor }}
key={item + i}
>
{item}
</div>
))
}
</div>
</div>
)
}
{
Expand Down Expand Up @@ -295,17 +309,15 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
selectedEntity.type === EntityType.Node ?
<div className="box-node-label" style={{ backgroundColor: selectedEntity.backgroundColor, color: selectedEntity.color }}>{selectedEntity.property}</div>
:
<div className='box-edge-type' style={{borderColor: selectedEntity.backgroundColor, color: selectedEntity.backgroundColor }}>{selectedEntity.property}</div>
<div className='box-edge-type' style={{ borderColor: selectedEntity.backgroundColor, color: selectedEntity.backgroundColor }}>{selectedEntity.property}</div>
}
<EuiButtonIcon color="text" onClick={() => setSelectedEntity(null)} display="empty" iconType="cross" aria-label="Close" />
</div>
<div className="info-props">
{
Object.keys(selectedEntity.props).map(k => [k, selectedEntity.props[k]]).reduce(
(a, b) => a.concat(b), []
).map(k =>
<div>{k}</div>
)
).map(k => <div>{k}</div>)
}
</div>
</div>
Expand Down
35 changes: 33 additions & 2 deletions redisinsight/ui/src/packages/redisgraph/src/graphd3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,10 @@ interface INode extends d3.SimulationNodeDatum {
properties: { [key: string]: string | number | object }
labels: string[]
color: string
angleX: number
angleY: number
links: string[]
targetLabels: {[label: string]: number}
}

interface IRelationship extends d3.SimulationLinkDatum<INode>{
Expand All @@ -592,6 +596,7 @@ interface IRelationship extends d3.SimulationLinkDatum<INode>{
shaftLength: number
midShaftPoint: Point
}
fetchedAutomatically?: boolean
}

interface IGraph {
Expand All @@ -615,11 +620,13 @@ export interface IGraphD3 {
updateWithD3Data: (d3Data: any) => void
updateWithGraphData: (graphData: any) => void
zoomFuncs: IZoomFuncs
toggleShowAutomaticEdges: () => void
}

function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
let info: any
let nodes: INode[]
let shouldShowAutomaticEdges = true;
let relationship: d3.Selection<SVGGElement, IRelationship, SVGGElement, any>
let labelCounter = 0;
let labels: { [key: string]: number } = { }
Expand Down Expand Up @@ -983,7 +990,7 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
function appendRelationship() {
return relationship.enter()
.append('g')
.attr('class', 'relationship')
.attr('class', r => `relationship relationship-${r.id}`)
.on('dblclick', function onRelationshipDoubleClick(event, d) {
if (typeof options.onRelationshipDoubleClick === 'function') {
options.onRelationshipDoubleClick(this, d, event)
Expand Down Expand Up @@ -1046,7 +1053,6 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {

function updateRelationships(r: IRelationship) {
Array.prototype.push.apply(relationships, r)

let a = svgRelationships.selectAll('.relationship')
relationship = svgRelationships
.selectAll('.relationship')
Expand All @@ -1071,14 +1077,31 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
n = n.filter(k => !nodeIds.includes(k.id))

let edgeIds = relationships.map(e => e.id)
const previousEdges = [...r]
r = r.filter(k => !edgeIds.includes(k.id))

if (relationship !== undefined) {
relationship.each(r => {
// If an edge is being fetchedAutomatically and is now added
// in new data, mark fetchedAutomatically to false.
if (r.fetchedAutomatically && previousEdges.map(k => k.id).includes(r.id)) {
r.fetchedAutomatically = false;
}
})
}

updateRelationships(r)
updateNodes(n)

simulation.nodes(nodes)
simulation.force('link', d3.forceLink(relationships).id((d: IRelationship) => d.id))

// Every time the function is run, do check whether automatically fetched edges must be rendered.
d3.selectAll('.relationship').each((r: IRelationship) => {
if (!shouldShowAutomaticEdges && r.fetchedAutomatically) {
d3.selectAll(`.relationship-${r.id}`).remove()
}
})
}

function graphDataToD3Data(data) {
Expand Down Expand Up @@ -1643,12 +1666,20 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {

resize()

function toggleShowAutomaticEdges() {
// Simply re-run the function. `updateNodesAndRelationships` internally checks for `shouldShowAutomaticEdges` prop to render edges that were fetched automatically.
shouldShowAutomaticEdges = !shouldShowAutomaticEdges;
updateNodesAndRelationships([], [])
simulation.restart()
}

return {
graphDataToD3Data,
size,
updateWithD3Data,
updateWithGraphData,
zoomFuncs,
toggleShowAutomaticEdges,
}
}

Expand Down
14 changes: 14 additions & 0 deletions redisinsight/ui/src/packages/redisgraph/src/styles/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,17 @@
.euiToolTip__arrow {
background-color: var(--tooltip-background) !important;
}


.automatic-edges-switch {
border-radius: 4px;
right: 4px;
position: absolute;
display: flex;
flex-direction: row;
color: var(--info-color);
margin-top: 12px !important;
margin-left: 24px !important;
font-size: 12px;
line-height: 18px;
}