Skip to content

Commit

Permalink
Reduce number of plots resize observers (#5097)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattseddon authored Dec 12, 2023
1 parent 80549c7 commit eaf4e15
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 116 deletions.
19 changes: 10 additions & 9 deletions webview/src/plots/components/customPlots/CustomPlots.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { DragEvent, useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
import { PlotsSection } from 'dvc/src/plots/webview/contract'
import React, { DragEvent, useEffect, useRef, useState } from 'react'
import cx from 'classnames'
import { useSelector } from 'react-redux'
import { NoPlotsAdded } from './NoPlotsAdded'
import { CustomPlotsGrid } from './CustomPlotsGrid'
import styles from '../styles.module.scss'
import { shouldUseVirtualizedGrid } from '../util'
import { Grid } from '../Grid'
import { LoadingSection, sectionIsLoading } from '../LoadingSection'
import { PlotsState } from '../../store'
import { changeOrderWithDraggedInfo } from '../../../util/array'
Expand Down Expand Up @@ -33,6 +32,8 @@ export const CustomPlots: React.FC<CustomPlotsProps> = ({ plotsIds }) => {
(state: PlotsState) => state.webview.selectedRevisions
)

const gridRef = useRef<HTMLDivElement>(null)

useEffect(() => {
setOrder(plotsIds)
}, [plotsIds])
Expand Down Expand Up @@ -82,15 +83,15 @@ export const CustomPlots: React.FC<CustomPlotsProps> = ({ plotsIds }) => {
onDragLeave={() => setOnSection(false)}
onDragOver={handleDragOver}
onDrop={handleDropAtTheEnd}
ref={gridRef}
>
<Grid
setOrder={setPlotsIdsOrder}
<CustomPlotsGrid
gridRef={gridRef}
nbItemsPerRow={nbItemsPerRow}
useVirtualizedGrid={useVirtualizedGrid}
order={order}
groupId="custom-plots"
parentDraggedOver={onSection}
sectionKey={PlotsSection.CUSTOM_PLOTS}
setOrder={setPlotsIdsOrder}
useVirtualizedGrid={useVirtualizedGrid}
/>
</div>
)
Expand Down
36 changes: 36 additions & 0 deletions webview/src/plots/components/customPlots/CustomPlotsGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { RefObject } from 'react'
import { PlotsSection } from 'dvc/src/plots/webview/contract'
import { useObserveGridDimensions } from '../../hooks/useObserveGridDimensions'
import { Grid } from '../Grid'

interface CustomPlotsGridProps {
gridRef: RefObject<HTMLDivElement>
nbItemsPerRow: number
order: string[]
parentDraggedOver: boolean
useVirtualizedGrid?: boolean
setOrder: (order: string[]) => void
}

export const CustomPlotsGrid: React.FC<CustomPlotsGridProps> = ({
gridRef,
nbItemsPerRow,
parentDraggedOver,
order,
setOrder,
useVirtualizedGrid
}) => {
useObserveGridDimensions(PlotsSection.CUSTOM_PLOTS, gridRef)

return (
<Grid
setOrder={setOrder}
nbItemsPerRow={nbItemsPerRow}
useVirtualizedGrid={useVirtualizedGrid}
order={order}
groupId="custom-plots"
parentDraggedOver={parentDraggedOver}
sectionKey={PlotsSection.CUSTOM_PLOTS}
/>
)
}
28 changes: 22 additions & 6 deletions webview/src/plots/components/customPlots/customPlotsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
import { addPlotsWithSnapshots, removePlots } from '../plotDataStore'

export interface CustomPlotsState extends Omit<CustomPlotsData, 'plots'> {
isCollapsed: boolean
hasData: boolean
hasItems: boolean
isCollapsed: boolean
isInDragAndDropMode: boolean
plotsIds: string[]
plotsSnapshots: { [key: string]: string }
isInDragAndDropMode: boolean
sectionHeight: number
sectionWidth: number
}

export const customPlotsInitialState: CustomPlotsState = {
Expand All @@ -29,7 +31,9 @@ export const customPlotsInitialState: CustomPlotsState = {
nbItemsPerRow:
DEFAULT_SECTION_NB_ITEMS_PER_ROW_OR_WIDTH[PlotsSection.CUSTOM_PLOTS],
plotsIds: [],
plotsSnapshots: {}
plotsSnapshots: {},
sectionHeight: 0,
sectionWidth: 0
}

export const customPlotsSlice = createSlice({
Expand Down Expand Up @@ -75,16 +79,28 @@ export const customPlotsSlice = createSlice({
plotsIds: plots?.map(plot => plot.id) || [],
plotsSnapshots
}
},
updateSectionDimensions: (
state,
action: PayloadAction<{ sectionHeight: number; sectionWidth: number }>
) => {
const { sectionHeight, sectionWidth } = action.payload
return {
...state,
sectionHeight,
sectionWidth
}
}
}
})

export const {
update,
setCollapsed,
changeSize,
clearState,
setCollapsed,
toggleDragAndDropMode,
clearState
update,
updateSectionDimensions
} = customPlotsSlice.actions

export default customPlotsSlice.reducer
203 changes: 129 additions & 74 deletions webview/src/plots/components/templatePlots/TemplatePlots.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { TemplatePlotGroup } from 'dvc/src/plots/webview/contract'
import React, { DragEvent, useState, useCallback } from 'react'
import { PlotsSection, TemplatePlotGroup } from 'dvc/src/plots/webview/contract'
import React, {
DragEvent,
useState,
useCallback,
useRef,
RefObject
} from 'react'
import cx from 'classnames'
import { useDispatch, useSelector } from 'react-redux'
import { AddedSection } from './AddedSection'
Expand All @@ -11,12 +17,117 @@ import { createIDWithIndex, getIDIndex } from '../../../util/ids'
import styles from '../styles.module.scss'
import { shouldUseVirtualizedGrid } from '../util'
import { PlotsState } from '../../store'
import { setDraggedOverGroup } from '../../../shared/components/dragDrop/dragDropSlice'
import {
DraggedInfo,
setDraggedOverGroup
} from '../../../shared/components/dragDrop/dragDropSlice'
import { isSameGroup } from '../../../shared/components/dragDrop/util'
import { changeOrderWithDraggedInfo } from '../../../util/array'
import { LoadingSection, sectionIsLoading } from '../LoadingSection'
import { reorderTemplatePlots } from '../../util/messages'
import { TooManyPlots } from '../TooManyPlots'
import { useObserveGridDimensions } from '../../hooks/useObserveGridDimensions'

interface TemplatePlotGroupsProps {
draggedRef: DraggedInfo
draggedOverGroup: string
gridRef: RefObject<HTMLDivElement>
handleDropInSection: (
draggedId: string,
draggedGroup: string,
groupId: string,
position?: number
) => void
handleEnteringSection: (groupId: string) => void
nbItemsPerRow: number
sections: PlotGroup[]
setSectionEntries: (index: number, entries: string[]) => void
setSections: (sections: PlotGroup[]) => void
}

const TemplatePlotGroups: React.FC<TemplatePlotGroupsProps> = ({
draggedOverGroup,
draggedRef,
gridRef,
handleDropInSection,
handleEnteringSection,
nbItemsPerRow,
sections,
setSectionEntries,
setSections
}) => {
useObserveGridDimensions(PlotsSection.TEMPLATE_PLOTS, gridRef)

return sections.map((section, i) => {
const groupId = createIDWithIndex(section.group, i)
const useVirtualizedGrid = shouldUseVirtualizedGrid(
Object.keys(section.entries).length,
nbItemsPerRow
)

const isMultiView = section.group === TemplatePlotGroup.MULTI_VIEW

const classes = cx(styles.sectionWrapper, {
[styles.multiViewPlotsGrid]: isMultiView,
[styles.singleViewPlotsGrid]: !isMultiView,
[styles.noBigGrid]: !useVirtualizedGrid
})

const handleDropAtTheEnd = () => {
handleEnteringSection('')
if (!draggedRef) {
return
}

if (draggedRef.group === groupId) {
const order = section.entries
const updatedSections = [...sections]

const newOrder = changeOrderWithDraggedInfo(order, draggedRef)
updatedSections[i] = {
...sections[i],
entries: newOrder
}
setSections(updatedSections)
} else if (isSameGroup(draggedRef.group, groupId)) {
handleDropInSection(
draggedRef.itemId,
draggedRef.group,
groupId,
section.entries.length
)
}
}

const handleDragOver = (e: DragEvent) => {
e.preventDefault()
handleEnteringSection(groupId)
}

return (
<div
key={groupId}
id={groupId}
data-testid={`plots-section_${groupId}`}
className={classes}
onDragEnter={() => handleEnteringSection(groupId)}
onDragOver={handleDragOver}
onDrop={handleDropAtTheEnd}
>
<TemplatePlotsGrid
groupId={groupId}
groupIndex={i}
onDropInSection={handleDropInSection}
multiView={isMultiView}
setSectionEntries={setSectionEntries}
useVirtualizedGrid={useVirtualizedGrid}
nbItemsPerRow={nbItemsPerRow}
parentDraggedOver={draggedOverGroup === groupId}
/>
</div>
)
})
}

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

const gridRef = useRef<HTMLDivElement>(null)

const [hoveredSection, setHoveredSection] = useState('')
const dispatch = useDispatch()

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

return (
<>
<div ref={gridRef}>
<AddedSection
{...newDropSection}
id={NewSectionBlock.TOP}
closestSection={firstSection}
/>
{sections.map((section, i) => {
const groupId = createIDWithIndex(section.group, i)
const useVirtualizedGrid = shouldUseVirtualizedGrid(
Object.keys(section.entries).length,
nbItemsPerRow
)

const isMultiView = section.group === TemplatePlotGroup.MULTI_VIEW

const classes = cx(styles.sectionWrapper, {
[styles.multiViewPlotsGrid]: isMultiView,
[styles.singleViewPlotsGrid]: !isMultiView,
[styles.noBigGrid]: !useVirtualizedGrid
})

const handleDropAtTheEnd = () => {
handleEnteringSection('')
if (!draggedRef) {
return
}

if (draggedRef.group === groupId) {
const order = section.entries
const updatedSections = [...sections]

const newOrder = changeOrderWithDraggedInfo(order, draggedRef)
updatedSections[i] = {
...sections[i],
entries: newOrder
}
setSections(updatedSections)
} else if (isSameGroup(draggedRef.group, groupId)) {
handleDropInSection(
draggedRef.itemId,
draggedRef.group,
groupId,
section.entries.length
)
}
}

const handleDragOver = (e: DragEvent) => {
e.preventDefault()
handleEnteringSection(groupId)
}

return (
<div
key={groupId}
id={groupId}
data-testid={`plots-section_${groupId}`}
className={classes}
onDragEnter={() => handleEnteringSection(groupId)}
onDragOver={handleDragOver}
onDrop={handleDropAtTheEnd}
>
<TemplatePlotsGrid
groupId={groupId}
groupIndex={i}
onDropInSection={handleDropInSection}
multiView={isMultiView}
setSectionEntries={setSectionEntries}
useVirtualizedGrid={useVirtualizedGrid}
nbItemsPerRow={nbItemsPerRow}
parentDraggedOver={draggedOverGroup === groupId}
/>
</div>
)
})}
<TemplatePlotGroups
draggedRef={draggedRef}
draggedOverGroup={draggedOverGroup}
gridRef={gridRef}
handleDropInSection={handleDropInSection}
handleEnteringSection={handleEnteringSection}
nbItemsPerRow={nbItemsPerRow}
sections={sections}
setSections={setSections}
setSectionEntries={setSectionEntries}
/>
<AddedSection
{...newDropSection}
id={NewSectionBlock.BOTTOM}
closestSection={lastSection}
/>
{shouldShowTooManyPlotsMessage && <TooManyPlots />}
</>
</div>
)
}
Loading

0 comments on commit eaf4e15

Please sign in to comment.