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'
39import cx from 'classnames'
410import { useDispatch , useSelector } from 'react-redux'
511import { AddedSection } from './AddedSection'
@@ -11,12 +17,117 @@ import { createIDWithIndex, getIDIndex } from '../../../util/ids'
1117import styles from '../styles.module.scss'
1218import { shouldUseVirtualizedGrid } from '../util'
1319import { PlotsState } from '../../store'
14- import { setDraggedOverGroup } from '../../../shared/components/dragDrop/dragDropSlice'
20+ import {
21+ DraggedInfo ,
22+ setDraggedOverGroup
23+ } from '../../../shared/components/dragDrop/dragDropSlice'
1524import { isSameGroup } from '../../../shared/components/dragDrop/util'
1625import { changeOrderWithDraggedInfo } from '../../../util/array'
1726import { LoadingSection , sectionIsLoading } from '../LoadingSection'
1827import { reorderTemplatePlots } from '../../util/messages'
1928import { 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
21132export 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