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
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ module.exports = {
cases: {
pascalCase: true
},
ignore: [/.*\.stories.tsx$/, /.*\.test\.tsx$/]
ignore: [/.*\.stories.tsx$/, /.*\.test\.tsx$/, /.*use.*\.tsx$/]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning for adding this? I'm not seeing any new files with this syntax 🤔

Copy link
Contributor Author

@sroy3 sroy3 Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useDragAndDrop.tsx there is some jsx in that file

}
]
}
Expand Down
10 changes: 4 additions & 6 deletions webview/src/plots/components/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1730,11 +1730,10 @@ describe('App', () => {
])
})

it('should show a drop target at the end of the custom plots when moving a plot inside the section but not over any other plot', () => {
it('should show a drop target at the end of the custom plots when moving a plot inside the section', () => {
renderAppWithOptionalDataInDragAndDropMode(
{
custom: customPlotsFixture,
template: templatePlotsFixture
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Q] From the test title it sounds like these plots are needed. Do the statements need to be updated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was never testing the other part. I guess we need to update the statement.

custom: customPlotsFixture
},
true
)
Expand All @@ -1746,11 +1745,10 @@ describe('App', () => {
expect(screen.getByTestId('plot_drop-target')).toBeInTheDocument()
})

it('should show a drop target a plot at the end of the custom plots when moving a plot inside the section but not over any other plot', () => {
it('should show a drop target a plot at the end of the custom plots when moving a plot inside the section', () => {
renderAppWithOptionalDataInDragAndDropMode(
{
custom: customPlotsFixture,
template: templatePlotsFixture
custom: customPlotsFixture
},
true
)
Expand Down
76 changes: 22 additions & 54 deletions webview/src/plots/components/DragAndDropGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,66 @@
import { PlotsSection } from 'dvc/src/plots/webview/contract'
import React from 'react'
import { useDispatch } from 'react-redux'
import cx from 'classnames'
import { DropTarget } from './DropTarget'
import { changeDragAndDropMode } from './util'
import styles from './styles.module.scss'
import { DragAndDropPlot } from './DragAndDropPlot'
import { plotDataStore } from './plotDataStore'
import { VirtualizedGrid } from '../../shared/components/virtualizedGrid/VirtualizedGrid'
import {
DragDropContainer,
OnDrop,
WrapperProps
} from '../../shared/components/dragDrop/DragDropContainer'
import { withScale } from '../../util/styles'
import { OnDrop } from '../../shared/hooks/useDragAndDrop'

interface DragAndDropGridProps {
order: string[]
setOrder: (order: string[]) => void
groupId: string
onDrop?: OnDrop
nbItemsPerRow: number
useVirtualizedGrid?: boolean
parentDraggedOver?: boolean
multiView?: boolean
sectionKey: PlotsSection
onDrop?: OnDrop
}

export const DragAndDropGrid: React.FC<DragAndDropGridProps> = ({
order,
setOrder,
groupId,
onDrop,
nbItemsPerRow,
useVirtualizedGrid,
parentDraggedOver,
multiView,
sectionKey
sectionKey,
onDrop
}) => {
const dispatch = useDispatch()
const plotClassName = cx(styles.plot, styles.dragAndDropPlot, {
[styles.multiViewPlot]: multiView
})
const items = order.map((plot: string) => {
const items = order.map((plot: string, i: number) => {
const colSpan =
(multiView &&
plotDataStore[PlotsSection.TEMPLATE_PLOTS][plot].revisions?.length) ||
plotDataStore[PlotsSection.TEMPLATE_PLOTS][plot]?.revisions?.length) ||
1

return (
<div
<DragAndDropPlot
key={plot}
id={plot}
className={plotClassName}
data-testid={`plot_${plot}`}
style={withScale(colSpan)}
>
<DragAndDropPlot plot={plot} sectionKey={sectionKey} />
</div>
plot={plot}
sectionKey={sectionKey}
className={plotClassName}
colSpan={colSpan}
group={groupId}
isParentDraggedOver={parentDraggedOver}
setOrder={setOrder}
order={order}
isLast={i === order.length - 1}
afterOnDrop={onDrop}
/>
)
})

const handleOnDrop = (
draggedId: string,
draggedGroup: string,
groupId: string,
position: number
) => {
changeDragAndDropMode(sectionKey, dispatch, true)
onDrop?.(draggedId, draggedGroup, groupId, position)
}

const handleDragEnd = () => {
changeDragAndDropMode(sectionKey, dispatch, true)
}

return (
<DragDropContainer
order={order}
setOrder={setOrder}
items={items}
group={groupId}
onDrop={handleOnDrop}
dropTarget={<DropTarget />}
wrapperComponent={
useVirtualizedGrid
? {
component: VirtualizedGrid as React.FC<WrapperProps>,
props: { nbItemsPerRow }
}
: undefined
}
parentDraggedOver={parentDraggedOver}
onDragEnd={handleDragEnd}
/>
return useVirtualizedGrid ? (
<VirtualizedGrid nbItemsPerRow={nbItemsPerRow}>{items}</VirtualizedGrid>
) : (
<>{items}</>
)
}
103 changes: 81 additions & 22 deletions webview/src/plots/components/DragAndDropPlot.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,121 @@
import cx from 'classnames'
import React, { useEffect, useRef } from 'react'
import React, {
DragEvent,
HTMLAttributes,
createRef,
useEffect,
useRef
} from 'react'
import { useDispatch } from 'react-redux'
import { PlotsSection } from 'dvc/src/plots/webview/contract'
import styles from './styles.module.scss'
import { changeDragAndDropMode } from './util'
import { DropTarget } from './DropTarget'
import { GripIcon } from '../../shared/components/dragDrop/GripIcon'
import { Icon } from '../../shared/components/Icon'
import { GraphLine } from '../../shared/components/icons'
import { withScale } from '../../util/styles'
import { OnDrop, useDragAndDrop } from '../../shared/hooks/useDragAndDrop'
import { useGetTitles } from '../hooks/useGetTitles'
import { DragDropItemWithTarget } from '../../shared/components/dragDrop/DragDropItemWithTarget'

interface DragAndDropPlotProps {
interface DragAndDropPlotProps extends HTMLAttributes<HTMLDivElement> {
plot: string
group: string
sectionKey: PlotsSection
colSpan: number
isParentDraggedOver?: boolean
setOrder: (order: string[]) => void
order: string[]
isLast?: boolean
afterOnDrop?: OnDrop
}

export const DragAndDropPlot: React.FC<DragAndDropPlotProps> = ({
plot,
sectionKey
sectionKey,
colSpan,
group,
isParentDraggedOver,
setOrder,
order,
isLast,
afterOnDrop,
...props
}) => {
const dispatch = useDispatch()
const dragAndDropTimeout = useRef(0)
const ref = createRef<HTMLDivElement>()
const titles = useGetTitles(sectionKey, plot)
const title = titles?.title || ''
const subtitle = titles?.subtitle || ''

const handleDragEnd = () => changeDragAndDropMode(sectionKey, dispatch, true)

const { isAfter, target, onDragStart, ...dragAndDropProps } = useDragAndDrop({
dropTarget: <DropTarget />,
group,
id: plot,
isLast,
isParentDraggedOver,
onDragEnd: handleDragEnd,
onDrop: afterOnDrop,
order,
setOrder,
style: withScale(colSpan)
})

useEffect(() => {
return () => {
clearTimeout(dragAndDropTimeout.current)
}
}, [])

const handleDragStart = (e: DragEvent<HTMLElement>) => {
onDragStart(e)
// Because the dragged element is being created while being dragged for plots in grids, there is a problem where
// the dragend event is not being associated with the element. Re-adding the event makes sure it's being called.
ref.current?.addEventListener('dragend', dragAndDropProps.onDragEnd)
}

const handleEndOfDragAndDrop = () => {
// This makes sure every onDrop and onDragEnd events have been called before switching to normal mode
dragAndDropTimeout.current = window.setTimeout(() => {
changeDragAndDropMode(sectionKey, dispatch, true)
handleDragEnd()
}, 100)
}

return (
<>
{
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div onMouseUp={handleEndOfDragAndDrop}>
<GripIcon className={styles.plotGripIcon} />
<DragDropItemWithTarget
isAfter={isAfter}
dropTarget={target || null}
draggable={<div />}
>
<div
{...props}
{...dragAndDropProps}
onDragStart={handleDragStart}
ref={ref}
>
{
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div onMouseUp={handleEndOfDragAndDrop}>
<GripIcon className={styles.plotGripIcon} />
</div>
}
<div className={styles.dragAndDropPlotContent}>
<h2 className={styles.dragAndDropPlotTitle}>{title}</h2>
{subtitle && (
<h3 className={styles.dragAndDropPlotSubtitle}>{subtitle}</h3>
)}
<Icon
icon={GraphLine}
className={cx(styles.dropIcon, styles.onPlotDropIcon)}
width={70}
height={70}
/>
</div>
}
<div className={styles.dragAndDropPlotContent}>
<h2 className={styles.dragAndDropPlotTitle}>{title}</h2>
{subtitle && (
<h3 className={styles.dragAndDropPlotSubtitle}>{subtitle}</h3>
)}
<Icon
icon={GraphLine}
className={cx(styles.dropIcon, styles.onPlotDropIcon)}
width={70}
height={70}
/>
</div>
</>
</DragDropItemWithTarget>
)
}
10 changes: 5 additions & 5 deletions webview/src/plots/components/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { NormalGrid, NormalGridProps } from './NormalGrid'
import { DragAndDropGrid } from './DragAndDropGrid'
import { isDragAndDropModeSelector } from './util'
import { PlotsState } from '../store'
import { OnDrop } from '../../shared/components/dragDrop/DragDropContainer'
import { OnDrop } from '../../shared/hooks/useDragAndDrop'

interface GridProps extends NormalGridProps {
setOrder: (order: string[]) => void
order: string[]
groupId: string
onDrop?: OnDrop
parentDraggedOver?: boolean
onDrop?: OnDrop
}

export const Grid: React.FC<GridProps> = ({
Expand All @@ -20,10 +20,10 @@ export const Grid: React.FC<GridProps> = ({
nbItemsPerRow,
order,
groupId,
onDrop,
parentDraggedOver,
multiView,
sectionKey
sectionKey,
onDrop
}) => {
const isInDragAndDropMode = useSelector((state: PlotsState) =>
isDragAndDropModeSelector(state, sectionKey)
Expand All @@ -36,9 +36,9 @@ export const Grid: React.FC<GridProps> = ({
multiView={multiView}
setOrder={setOrder}
groupId={groupId}
onDrop={onDrop}
parentDraggedOver={parentDraggedOver}
sectionKey={sectionKey}
onDrop={onDrop}
/>
) : (
<NormalGrid
Expand Down
2 changes: 1 addition & 1 deletion webview/src/plots/components/NormalGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const NormalGrid: React.FC<NormalGridProps> = ({
})

return useVirtualizedGrid ? (
<VirtualizedGrid nbItemsPerRow={nbItemsPerRow} items={plots} />
<VirtualizedGrid nbItemsPerRow={nbItemsPerRow}>{plots}</VirtualizedGrid>
) : (
<>{plots}</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,14 +535,9 @@ describe('ComparisonTable', () => {

const [headerWrapper] = getHeaders()

// eslint-disable-next-line testing-library/no-node-access
expect(headerWrapper.childElementCount).toBe(2)
expect(
// eslint-disable-next-line testing-library/no-node-access
Object.values(headerWrapper.children)
.map(child => child.id)
.includes(endingNode.id)
).toBe(true)
within(headerWrapper).getByTestId('comparison-drop-target')
).toBeInTheDocument()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Q] How do these assertions differ/relate to one another?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not wrapped the exact same way, but the test checks the same thing, it was just not written in a clear way before.

})

it('should not change the order when dropping a header in its own spot', () => {
Expand Down
Loading