Skip to content

Commit eaf4e15

Browse files
authored
Reduce number of plots resize observers (#5097)
1 parent 80549c7 commit eaf4e15

File tree

7 files changed

+285
-116
lines changed

7 files changed

+285
-116
lines changed

webview/src/plots/components/customPlots/CustomPlots.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import React, { DragEvent, useEffect, useState } from 'react'
2-
import { useSelector } from 'react-redux'
3-
import { PlotsSection } from 'dvc/src/plots/webview/contract'
1+
import React, { DragEvent, useEffect, useRef, useState } from 'react'
42
import cx from 'classnames'
3+
import { useSelector } from 'react-redux'
54
import { NoPlotsAdded } from './NoPlotsAdded'
5+
import { CustomPlotsGrid } from './CustomPlotsGrid'
66
import styles from '../styles.module.scss'
77
import { shouldUseVirtualizedGrid } from '../util'
8-
import { Grid } from '../Grid'
98
import { LoadingSection, sectionIsLoading } from '../LoadingSection'
109
import { PlotsState } from '../../store'
1110
import { changeOrderWithDraggedInfo } from '../../../util/array'
@@ -33,6 +32,8 @@ export const CustomPlots: React.FC<CustomPlotsProps> = ({ plotsIds }) => {
3332
(state: PlotsState) => state.webview.selectedRevisions
3433
)
3534

35+
const gridRef = useRef<HTMLDivElement>(null)
36+
3637
useEffect(() => {
3738
setOrder(plotsIds)
3839
}, [plotsIds])
@@ -82,15 +83,15 @@ export const CustomPlots: React.FC<CustomPlotsProps> = ({ plotsIds }) => {
8283
onDragLeave={() => setOnSection(false)}
8384
onDragOver={handleDragOver}
8485
onDrop={handleDropAtTheEnd}
86+
ref={gridRef}
8587
>
86-
<Grid
87-
setOrder={setPlotsIdsOrder}
88+
<CustomPlotsGrid
89+
gridRef={gridRef}
8890
nbItemsPerRow={nbItemsPerRow}
89-
useVirtualizedGrid={useVirtualizedGrid}
9091
order={order}
91-
groupId="custom-plots"
9292
parentDraggedOver={onSection}
93-
sectionKey={PlotsSection.CUSTOM_PLOTS}
93+
setOrder={setPlotsIdsOrder}
94+
useVirtualizedGrid={useVirtualizedGrid}
9495
/>
9596
</div>
9697
)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React, { RefObject } from 'react'
2+
import { PlotsSection } from 'dvc/src/plots/webview/contract'
3+
import { useObserveGridDimensions } from '../../hooks/useObserveGridDimensions'
4+
import { Grid } from '../Grid'
5+
6+
interface CustomPlotsGridProps {
7+
gridRef: RefObject<HTMLDivElement>
8+
nbItemsPerRow: number
9+
order: string[]
10+
parentDraggedOver: boolean
11+
useVirtualizedGrid?: boolean
12+
setOrder: (order: string[]) => void
13+
}
14+
15+
export const CustomPlotsGrid: React.FC<CustomPlotsGridProps> = ({
16+
gridRef,
17+
nbItemsPerRow,
18+
parentDraggedOver,
19+
order,
20+
setOrder,
21+
useVirtualizedGrid
22+
}) => {
23+
useObserveGridDimensions(PlotsSection.CUSTOM_PLOTS, gridRef)
24+
25+
return (
26+
<Grid
27+
setOrder={setOrder}
28+
nbItemsPerRow={nbItemsPerRow}
29+
useVirtualizedGrid={useVirtualizedGrid}
30+
order={order}
31+
groupId="custom-plots"
32+
parentDraggedOver={parentDraggedOver}
33+
sectionKey={PlotsSection.CUSTOM_PLOTS}
34+
/>
35+
)
36+
}

webview/src/plots/components/customPlots/customPlotsSlice.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import {
1010
import { addPlotsWithSnapshots, removePlots } from '../plotDataStore'
1111

1212
export interface CustomPlotsState extends Omit<CustomPlotsData, 'plots'> {
13-
isCollapsed: boolean
1413
hasData: boolean
1514
hasItems: boolean
15+
isCollapsed: boolean
16+
isInDragAndDropMode: boolean
1617
plotsIds: string[]
1718
plotsSnapshots: { [key: string]: string }
18-
isInDragAndDropMode: boolean
19+
sectionHeight: number
20+
sectionWidth: number
1921
}
2022

2123
export const customPlotsInitialState: CustomPlotsState = {
@@ -29,7 +31,9 @@ export const customPlotsInitialState: CustomPlotsState = {
2931
nbItemsPerRow:
3032
DEFAULT_SECTION_NB_ITEMS_PER_ROW_OR_WIDTH[PlotsSection.CUSTOM_PLOTS],
3133
plotsIds: [],
32-
plotsSnapshots: {}
34+
plotsSnapshots: {},
35+
sectionHeight: 0,
36+
sectionWidth: 0
3337
}
3438

3539
export const customPlotsSlice = createSlice({
@@ -75,16 +79,28 @@ export const customPlotsSlice = createSlice({
7579
plotsIds: plots?.map(plot => plot.id) || [],
7680
plotsSnapshots
7781
}
82+
},
83+
updateSectionDimensions: (
84+
state,
85+
action: PayloadAction<{ sectionHeight: number; sectionWidth: number }>
86+
) => {
87+
const { sectionHeight, sectionWidth } = action.payload
88+
return {
89+
...state,
90+
sectionHeight,
91+
sectionWidth
92+
}
7893
}
7994
}
8095
})
8196

8297
export const {
83-
update,
84-
setCollapsed,
8598
changeSize,
99+
clearState,
100+
setCollapsed,
86101
toggleDragAndDropMode,
87-
clearState
102+
update,
103+
updateSectionDimensions
88104
} = customPlotsSlice.actions
89105

90106
export default customPlotsSlice.reducer

webview/src/plots/components/templatePlots/TemplatePlots.tsx

Lines changed: 129 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import { TemplatePlotGroup } from 'dvc/src/plots/webview/contract'
2-
import React, { DragEvent, useState, useCallback } from 'react'
1+
import { PlotsSection, TemplatePlotGroup } from 'dvc/src/plots/webview/contract'
2+
import React, {
3+
DragEvent,
4+
useState,
5+
useCallback,
6+
useRef,
7+
RefObject
8+
} from 'react'
39
import cx from 'classnames'
410
import { useDispatch, useSelector } from 'react-redux'
511
import { AddedSection } from './AddedSection'
@@ -11,12 +17,117 @@ import { createIDWithIndex, getIDIndex } from '../../../util/ids'
1117
import styles from '../styles.module.scss'
1218
import { shouldUseVirtualizedGrid } from '../util'
1319
import { PlotsState } from '../../store'
14-
import { setDraggedOverGroup } from '../../../shared/components/dragDrop/dragDropSlice'
20+
import {
21+
DraggedInfo,
22+
setDraggedOverGroup
23+
} from '../../../shared/components/dragDrop/dragDropSlice'
1524
import { isSameGroup } from '../../../shared/components/dragDrop/util'
1625
import { changeOrderWithDraggedInfo } from '../../../util/array'
1726
import { LoadingSection, sectionIsLoading } from '../LoadingSection'
1827
import { reorderTemplatePlots } from '../../util/messages'
1928
import { TooManyPlots } from '../TooManyPlots'
29+
import { useObserveGridDimensions } from '../../hooks/useObserveGridDimensions'
30+
31+
interface TemplatePlotGroupsProps {
32+
draggedRef: DraggedInfo
33+
draggedOverGroup: string
34+
gridRef: RefObject<HTMLDivElement>
35+
handleDropInSection: (
36+
draggedId: string,
37+
draggedGroup: string,
38+
groupId: string,
39+
position?: number
40+
) => void
41+
handleEnteringSection: (groupId: string) => void
42+
nbItemsPerRow: number
43+
sections: PlotGroup[]
44+
setSectionEntries: (index: number, entries: string[]) => void
45+
setSections: (sections: PlotGroup[]) => void
46+
}
47+
48+
const TemplatePlotGroups: React.FC<TemplatePlotGroupsProps> = ({
49+
draggedOverGroup,
50+
draggedRef,
51+
gridRef,
52+
handleDropInSection,
53+
handleEnteringSection,
54+
nbItemsPerRow,
55+
sections,
56+
setSectionEntries,
57+
setSections
58+
}) => {
59+
useObserveGridDimensions(PlotsSection.TEMPLATE_PLOTS, gridRef)
60+
61+
return sections.map((section, i) => {
62+
const groupId = createIDWithIndex(section.group, i)
63+
const useVirtualizedGrid = shouldUseVirtualizedGrid(
64+
Object.keys(section.entries).length,
65+
nbItemsPerRow
66+
)
67+
68+
const isMultiView = section.group === TemplatePlotGroup.MULTI_VIEW
69+
70+
const classes = cx(styles.sectionWrapper, {
71+
[styles.multiViewPlotsGrid]: isMultiView,
72+
[styles.singleViewPlotsGrid]: !isMultiView,
73+
[styles.noBigGrid]: !useVirtualizedGrid
74+
})
75+
76+
const handleDropAtTheEnd = () => {
77+
handleEnteringSection('')
78+
if (!draggedRef) {
79+
return
80+
}
81+
82+
if (draggedRef.group === groupId) {
83+
const order = section.entries
84+
const updatedSections = [...sections]
85+
86+
const newOrder = changeOrderWithDraggedInfo(order, draggedRef)
87+
updatedSections[i] = {
88+
...sections[i],
89+
entries: newOrder
90+
}
91+
setSections(updatedSections)
92+
} else if (isSameGroup(draggedRef.group, groupId)) {
93+
handleDropInSection(
94+
draggedRef.itemId,
95+
draggedRef.group,
96+
groupId,
97+
section.entries.length
98+
)
99+
}
100+
}
101+
102+
const handleDragOver = (e: DragEvent) => {
103+
e.preventDefault()
104+
handleEnteringSection(groupId)
105+
}
106+
107+
return (
108+
<div
109+
key={groupId}
110+
id={groupId}
111+
data-testid={`plots-section_${groupId}`}
112+
className={classes}
113+
onDragEnter={() => handleEnteringSection(groupId)}
114+
onDragOver={handleDragOver}
115+
onDrop={handleDropAtTheEnd}
116+
>
117+
<TemplatePlotsGrid
118+
groupId={groupId}
119+
groupIndex={i}
120+
onDropInSection={handleDropInSection}
121+
multiView={isMultiView}
122+
setSectionEntries={setSectionEntries}
123+
useVirtualizedGrid={useVirtualizedGrid}
124+
nbItemsPerRow={nbItemsPerRow}
125+
parentDraggedOver={draggedOverGroup === groupId}
126+
/>
127+
</div>
128+
)
129+
})
130+
}
20131

21132
export enum NewSectionBlock {
22133
TOP = 'drop-section-top',
@@ -37,6 +148,8 @@ export const TemplatePlots: React.FC = () => {
37148
(state: PlotsState) => state.webview.selectedRevisions
38149
)
39150

151+
const gridRef = useRef<HTMLDivElement>(null)
152+
40153
const [hoveredSection, setHoveredSection] = useState('')
41154
const dispatch = useDispatch()
42155

@@ -151,87 +264,29 @@ export const TemplatePlots: React.FC = () => {
151264
}
152265

153266
return (
154-
<>
267+
<div ref={gridRef}>
155268
<AddedSection
156269
{...newDropSection}
157270
id={NewSectionBlock.TOP}
158271
closestSection={firstSection}
159272
/>
160-
{sections.map((section, i) => {
161-
const groupId = createIDWithIndex(section.group, i)
162-
const useVirtualizedGrid = shouldUseVirtualizedGrid(
163-
Object.keys(section.entries).length,
164-
nbItemsPerRow
165-
)
166-
167-
const isMultiView = section.group === TemplatePlotGroup.MULTI_VIEW
168-
169-
const classes = cx(styles.sectionWrapper, {
170-
[styles.multiViewPlotsGrid]: isMultiView,
171-
[styles.singleViewPlotsGrid]: !isMultiView,
172-
[styles.noBigGrid]: !useVirtualizedGrid
173-
})
174-
175-
const handleDropAtTheEnd = () => {
176-
handleEnteringSection('')
177-
if (!draggedRef) {
178-
return
179-
}
180-
181-
if (draggedRef.group === groupId) {
182-
const order = section.entries
183-
const updatedSections = [...sections]
184-
185-
const newOrder = changeOrderWithDraggedInfo(order, draggedRef)
186-
updatedSections[i] = {
187-
...sections[i],
188-
entries: newOrder
189-
}
190-
setSections(updatedSections)
191-
} else if (isSameGroup(draggedRef.group, groupId)) {
192-
handleDropInSection(
193-
draggedRef.itemId,
194-
draggedRef.group,
195-
groupId,
196-
section.entries.length
197-
)
198-
}
199-
}
200-
201-
const handleDragOver = (e: DragEvent) => {
202-
e.preventDefault()
203-
handleEnteringSection(groupId)
204-
}
205-
206-
return (
207-
<div
208-
key={groupId}
209-
id={groupId}
210-
data-testid={`plots-section_${groupId}`}
211-
className={classes}
212-
onDragEnter={() => handleEnteringSection(groupId)}
213-
onDragOver={handleDragOver}
214-
onDrop={handleDropAtTheEnd}
215-
>
216-
<TemplatePlotsGrid
217-
groupId={groupId}
218-
groupIndex={i}
219-
onDropInSection={handleDropInSection}
220-
multiView={isMultiView}
221-
setSectionEntries={setSectionEntries}
222-
useVirtualizedGrid={useVirtualizedGrid}
223-
nbItemsPerRow={nbItemsPerRow}
224-
parentDraggedOver={draggedOverGroup === groupId}
225-
/>
226-
</div>
227-
)
228-
})}
273+
<TemplatePlotGroups
274+
draggedRef={draggedRef}
275+
draggedOverGroup={draggedOverGroup}
276+
gridRef={gridRef}
277+
handleDropInSection={handleDropInSection}
278+
handleEnteringSection={handleEnteringSection}
279+
nbItemsPerRow={nbItemsPerRow}
280+
sections={sections}
281+
setSections={setSections}
282+
setSectionEntries={setSectionEntries}
283+
/>
229284
<AddedSection
230285
{...newDropSection}
231286
id={NewSectionBlock.BOTTOM}
232287
closestSection={lastSection}
233288
/>
234289
{shouldShowTooManyPlotsMessage && <TooManyPlots />}
235-
</>
290+
</div>
236291
)
237292
}

0 commit comments

Comments
 (0)