Skip to content

Commit 6b4ff75

Browse files
Merge branch 'main' into feature/e2e-create-consumer-group
2 parents 425d6f0 + bae716b commit 6b4ff75

File tree

14 files changed

+262
-56
lines changed

14 files changed

+262
-56
lines changed

redisinsight/api/src/modules/shared/services/instances-business/instances-analytics.service.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ describe('InstancesAnalytics', () => {
275275
TelemetryEvents.RedisInstanceDeleted,
276276
{
277277
databaseId: mockDatabaseInstanceDto.id,
278+
provider: mockDatabaseInstanceDto.provider,
278279
},
279280
);
280281
});

redisinsight/api/src/modules/shared/services/instances-business/instances-analytics.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export class InstancesAnalyticsService extends TelemetryBaseService {
109109
TelemetryEvents.RedisInstanceDeleted,
110110
{
111111
databaseId: instance.id,
112+
provider: instance.provider,
112113
},
113114
);
114115
}

redisinsight/ui/src/packages/redisgraph/src/Graph.tsx

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { useEffect, useRef, useState, useMemo } from 'react'
1+
import React, { useEffect, useRef, useState, useMemo } from 'react'
22
import * as d3 from 'd3'
33
import { executeRedisCommand } from 'redisinsight-plugin-sdk'
44
import {
55
EuiButtonIcon,
66
EuiToolTip,
7+
EuiSwitch,
78
} from '@elastic/eui'
89
import Graphd3, { IGraphD3 } from './graphd3'
910
import { responseParser } from './parser'
@@ -49,6 +50,7 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
4950
const [container, setContainer] = useState<IGraphD3>(null)
5051
const [selectedEntity, setSelectedEntity] = useState<ISelectedEntityProps | null>(null)
5152
const [start, setStart] = useState<boolean>(false)
53+
const [showAutomaticEdges, setShowAutomaticEdges] = useState(true);
5254

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

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

251253
return (
252254
<div className="core-container" data-testid="query-graph-container">
255+
<div className="automatic-edges-switch">
256+
<EuiToolTip position="bottom" delay="long" content="Toggle visibility of automatically fetched relationships">
257+
<EuiSwitch
258+
label="All relationships"
259+
checked={showAutomaticEdges}
260+
onChange={() => {
261+
container.toggleShowAutomaticEdges()
262+
setShowAutomaticEdges(!showAutomaticEdges)
263+
}}
264+
/>
265+
</EuiToolTip>
266+
</div>
253267
<div className="d3-info">
254268
<div className="graph-legends">
255269
{
@@ -259,14 +273,14 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
259273
Object.keys(nodeLabels).map((item, i) => (
260274
<div
261275
className="box-node-label"
262-
style={{backgroundColor: labelColors(item).color, color: labelColors(item).textColor}}
276+
style={{ backgroundColor: labelColors(item).color, color: labelColors(item).textColor }}
263277
key={item + i}
264278
>
265279
{item}
266280
</div>
267281
))
268282
}
269-
</div>
283+
</div>
270284
)
271285
}
272286
{
@@ -295,17 +309,15 @@ export default function Graph(props: { graphKey: string, data: any[] }) {
295309
selectedEntity.type === EntityType.Node ?
296310
<div className="box-node-label" style={{ backgroundColor: selectedEntity.backgroundColor, color: selectedEntity.color }}>{selectedEntity.property}</div>
297311
:
298-
<div className='box-edge-type' style={{borderColor: selectedEntity.backgroundColor, color: selectedEntity.backgroundColor }}>{selectedEntity.property}</div>
312+
<div className='box-edge-type' style={{ borderColor: selectedEntity.backgroundColor, color: selectedEntity.backgroundColor }}>{selectedEntity.property}</div>
299313
}
300314
<EuiButtonIcon color="text" onClick={() => setSelectedEntity(null)} display="empty" iconType="cross" aria-label="Close" />
301315
</div>
302316
<div className="info-props">
303317
{
304318
Object.keys(selectedEntity.props).map(k => [k, selectedEntity.props[k]]).reduce(
305319
(a, b) => a.concat(b), []
306-
).map(k =>
307-
<div>{k}</div>
308-
)
320+
).map(k => <div>{k}</div>)
309321
}
310322
</div>
311323
</div>

redisinsight/ui/src/packages/redisgraph/src/graphd3.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@ interface INode extends d3.SimulationNodeDatum {
571571
properties: { [key: string]: string | number | object }
572572
labels: string[]
573573
color: string
574+
angleX: number
575+
angleY: number
576+
links: string[]
577+
targetLabels: {[label: string]: number}
574578
}
575579

576580
interface IRelationship extends d3.SimulationLinkDatum<INode>{
@@ -592,6 +596,7 @@ interface IRelationship extends d3.SimulationLinkDatum<INode>{
592596
shaftLength: number
593597
midShaftPoint: Point
594598
}
599+
fetchedAutomatically?: boolean
595600
}
596601

597602
interface IGraph {
@@ -615,11 +620,13 @@ export interface IGraphD3 {
615620
updateWithD3Data: (d3Data: any) => void
616621
updateWithGraphData: (graphData: any) => void
617622
zoomFuncs: IZoomFuncs
623+
toggleShowAutomaticEdges: () => void
618624
}
619625

620626
function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
621627
let info: any
622628
let nodes: INode[]
629+
let shouldShowAutomaticEdges = true;
623630
let relationship: d3.Selection<SVGGElement, IRelationship, SVGGElement, any>
624631
let labelCounter = 0;
625632
let labels: { [key: string]: number } = { }
@@ -983,7 +990,7 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
983990
function appendRelationship() {
984991
return relationship.enter()
985992
.append('g')
986-
.attr('class', 'relationship')
993+
.attr('class', r => `relationship relationship-${r.id}`)
987994
.on('dblclick', function onRelationshipDoubleClick(event, d) {
988995
if (typeof options.onRelationshipDoubleClick === 'function') {
989996
options.onRelationshipDoubleClick(this, d, event)
@@ -1046,7 +1053,6 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
10461053

10471054
function updateRelationships(r: IRelationship) {
10481055
Array.prototype.push.apply(relationships, r)
1049-
10501056
let a = svgRelationships.selectAll('.relationship')
10511057
relationship = svgRelationships
10521058
.selectAll('.relationship')
@@ -1071,14 +1077,31 @@ function GraphD3(_selector: HTMLDivElement, _options: any): IGraphD3 {
10711077
n = n.filter(k => !nodeIds.includes(k.id))
10721078

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

1083+
if (relationship !== undefined) {
1084+
relationship.each(r => {
1085+
// If an edge is being fetchedAutomatically and is now added
1086+
// in new data, mark fetchedAutomatically to false.
1087+
if (r.fetchedAutomatically && previousEdges.map(k => k.id).includes(r.id)) {
1088+
r.fetchedAutomatically = false;
1089+
}
1090+
})
1091+
}
1092+
10761093
updateRelationships(r)
10771094
updateNodes(n)
10781095

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

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

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

16441667
resize()
16451668

1669+
function toggleShowAutomaticEdges() {
1670+
// Simply re-run the function. `updateNodesAndRelationships` internally checks for `shouldShowAutomaticEdges` prop to render edges that were fetched automatically.
1671+
shouldShowAutomaticEdges = !shouldShowAutomaticEdges;
1672+
updateNodesAndRelationships([], [])
1673+
simulation.restart()
1674+
}
1675+
16461676
return {
16471677
graphDataToD3Data,
16481678
size,
16491679
updateWithD3Data,
16501680
updateWithGraphData,
16511681
zoomFuncs,
1682+
toggleShowAutomaticEdges,
16521683
}
16531684
}
16541685

redisinsight/ui/src/packages/redisgraph/src/styles/styles.less

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,17 @@
263263
.euiToolTip__arrow {
264264
background-color: var(--tooltip-background) !important;
265265
}
266+
267+
268+
.automatic-edges-switch {
269+
border-radius: 4px;
270+
right: 4px;
271+
position: absolute;
272+
display: flex;
273+
flex-direction: row;
274+
color: var(--info-color);
275+
margin-top: 12px !important;
276+
margin-left: 24px !important;
277+
font-size: 12px;
278+
line-height: 18px;
279+
}

redisinsight/ui/src/pages/browser/components/key-details-add-items/add-stream-group/AddStreamGroup.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ import {
1212
import cx from 'classnames'
1313
import React, { ChangeEvent, useEffect, useState } from 'react'
1414
import { useDispatch, useSelector } from 'react-redux'
15-
import { lastDeliveredIDTooltipText } from 'uiSrc/constants/texts'
15+
import { useParams } from 'react-router-dom'
1616

17+
import { lastDeliveredIDTooltipText } from 'uiSrc/constants/texts'
1718
import { selectedKeyDataSelector } from 'uiSrc/slices/browser/keys'
1819
import { addNewGroupAction } from 'uiSrc/slices/browser/stream'
1920
import { consumerGroupIdRegex, validateConsumerGroupId } from 'uiSrc/utils'
2021
import { CreateConsumerGroupsDto } from 'apiSrc/modules/browser/dto/stream.dto'
22+
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
2123

2224
import styles from './styles.module.scss'
2325

@@ -35,6 +37,8 @@ const AddStreamGroup = (props: Props) => {
3537
const [idError, setIdError] = useState<string>('')
3638
const [isIdFocused, setIsIdFocused] = useState<boolean>(false)
3739

40+
const { instanceId } = useParams<{ instanceId: string }>()
41+
3842
const dispatch = useDispatch()
3943

4044
useEffect(() => {
@@ -50,6 +54,16 @@ const AddStreamGroup = (props: Props) => {
5054
setIdError('')
5155
}, [id])
5256

57+
const onSuccessAdded = () => {
58+
onCancel()
59+
sendEventTelemetry({
60+
event: TelemetryEvent.STREAM_CONSUMER_GROUP_CREATED,
61+
eventData: {
62+
databaseId: instanceId,
63+
}
64+
})
65+
}
66+
5367
const submitData = () => {
5468
if (isFormValid) {
5569
const data: CreateConsumerGroupsDto = {
@@ -59,7 +73,7 @@ const AddStreamGroup = (props: Props) => {
5973
lastDeliveredId: id,
6074
}],
6175
}
62-
dispatch(addNewGroupAction(data, onCancel))
76+
dispatch(addNewGroupAction(data, onSuccessAdded))
6377
}
6478
}
6579

redisinsight/ui/src/pages/browser/components/stream-details/consumers-view/ConsumersViewWrapper.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { useCallback, useEffect, useState } from 'react'
1+
import React, { useEffect, useState } from 'react'
22
import { useDispatch, useSelector } from 'react-redux'
3+
import { useParams } from 'react-router-dom'
34
import { EuiToolTip, EuiText } from '@elastic/eui'
45

56
import {
@@ -16,6 +17,7 @@ import { StreamViewType } from 'uiSrc/slices/interfaces/stream'
1617
import { numberWithSpaces } from 'uiSrc/utils/numbers'
1718
import { selectedKeyDataSelector, updateSelectedKeyRefreshTime } from 'uiSrc/slices/browser/keys'
1819
import { formatLongName } from 'uiSrc/utils'
20+
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
1921

2022
import { ConsumerDto } from 'apiSrc/modules/browser/dto/stream.dto'
2123
import ConsumersView from './ConsumersView'
@@ -37,6 +39,8 @@ const ConsumersViewWrapper = (props: Props) => {
3739
data: loadedConsumers = [],
3840
} = useSelector(selectedGroupSelector) ?? {}
3941

42+
const { instanceId } = useParams<{ instanceId: string }>()
43+
4044
const dispatch = useDispatch()
4145

4246
const [deleting, setDeleting] = useState<string>('')
@@ -45,19 +49,28 @@ const ConsumersViewWrapper = (props: Props) => {
4549
dispatch(updateSelectedKeyRefreshTime(lastRefreshTime))
4650
}, [])
4751

48-
const closePopover = useCallback(() => {
52+
const closePopover = () => {
4953
setDeleting('')
50-
}, [])
54+
}
5155

52-
const showPopover = useCallback((consumer = '') => {
56+
const showPopover = (consumer = '') => {
5357
setDeleting(`${consumer + suffix}`)
54-
}, [])
58+
}
5559

56-
const handleDeleteConsumer = (consumerName = '') => {
57-
dispatch(deleteConsumersAction(key, selectedGroupName, [consumerName]))
60+
const onSuccessDeletedConsumer = () => {
61+
sendEventTelemetry({
62+
event: TelemetryEvent.STREAM_CONSUMER_DELETED,
63+
eventData: {
64+
databaseId: instanceId,
65+
}
66+
})
5867
closePopover()
5968
}
6069

70+
const handleDeleteConsumer = (consumerName = '') => {
71+
dispatch(deleteConsumersAction(key, selectedGroupName, [consumerName], onSuccessDeletedConsumer))
72+
}
73+
6174
const handleRemoveIconClick = () => {
6275
// sendEventTelemetry({
6376
// event: getBasedOnViewTypeEvent(

0 commit comments

Comments
 (0)