fix(dashboard): invalid drop item on a tab (#28507)

This commit is contained in:
JUST.in DO IT 2024-05-15 04:48:14 -07:00 committed by GitHub
parent 821c7d7f2c
commit 65e0d54fa5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 97 additions and 4 deletions

View File

@ -55,8 +55,11 @@ export default function handleDrop(props, monitor, Component) {
}, },
}; };
const shouldAppendToChildren =
typeof dropToChild === 'function' ? dropToChild(draggingItem) : dropToChild;
// simplest case, append as child // simplest case, append as child
if (dropToChild) { if (shouldAppendToChildren) {
dropResult.destination = { dropResult.destination = {
id: component.id, id: component.id,
type: component.type, type: component.type,
@ -74,7 +77,9 @@ export default function handleDrop(props, monitor, Component) {
const sameParent = const sameParent =
parentComponent && draggingItem.parentId === parentComponent.id; parentComponent && draggingItem.parentId === parentComponent.id;
const sameParentLowerIndex = const sameParentLowerIndex =
sameParent && draggingItem.index < componentIndex; sameParent &&
draggingItem.index < componentIndex &&
draggingItem.type !== component.type;
const nextIndex = sameParentLowerIndex const nextIndex = sameParentLowerIndex
? componentIndex - 1 ? componentIndex - 1

View File

@ -32,6 +32,7 @@ import DragDroppable, {
Droppable, Droppable,
} from 'src/dashboard/components/dnd/DragDroppable'; } from 'src/dashboard/components/dnd/DragDroppable';
import { componentShape } from 'src/dashboard/util/propShapes'; import { componentShape } from 'src/dashboard/util/propShapes';
import { TAB_TYPE } from 'src/dashboard/util/componentTypes';
export const RENDER_TAB = 'RENDER_TAB'; export const RENDER_TAB = 'RENDER_TAB';
export const RENDER_TAB_CONTENT = 'RENDER_TAB_CONTENT'; export const RENDER_TAB_CONTENT = 'RENDER_TAB_CONTENT';
@ -139,6 +140,10 @@ class Tab extends React.PureComponent {
} }
} }
shouldDropToChild(item) {
return item.type !== TAB_TYPE;
}
renderTabContent() { renderTabContent() {
const { const {
component: tabComponent, component: tabComponent,
@ -275,6 +280,7 @@ class Tab extends React.PureComponent {
onDrop={this.handleDrop} onDrop={this.handleDrop}
onHover={this.handleOnHover} onHover={this.handleOnHover}
editMode={editMode} editMode={editMode}
dropToChild={this.shouldDropToChild}
> >
{({ dropIndicatorProps, dragSourceRef }) => ( {({ dropIndicatorProps, dragSourceRef }) => (
<TabTitleContainer <TabTitleContainer

View File

@ -19,12 +19,18 @@
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import React from 'react'; import React from 'react';
import { render, screen } from 'spec/helpers/testing-library'; import {
fireEvent,
render,
screen,
waitFor,
} from 'spec/helpers/testing-library';
import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
import EditableTitle from 'src/components/EditableTitle'; import EditableTitle from 'src/components/EditableTitle';
import { setEditMode } from 'src/dashboard/actions/dashboardState'; import { setEditMode } from 'src/dashboard/actions/dashboardState';
import Tab from './Tab'; import Tab from './Tab';
import Markdown from './Markdown';
jest.mock('src/dashboard/containers/DashboardComponent', () => jest.mock('src/dashboard/containers/DashboardComponent', () =>
jest.fn(() => <div data-test="DashboardComponent" />), jest.fn(() => <div data-test="DashboardComponent" />),
@ -128,6 +134,82 @@ test('Render tab (no content) editMode:true', () => {
expect(getByTestId('dragdroppable-object')).toBeInTheDocument(); expect(getByTestId('dragdroppable-object')).toBeInTheDocument();
}); });
test('Drop on a tab', async () => {
const props = createProps();
const mockOnDropOnTab = jest.fn();
render(
<>
<Tab {...props} renderType="RENDER_TAB" editMode />
<Tab
{...props}
renderType="RENDER_TAB"
index={2}
component={{
...props.component,
id: 'TAB-Next-',
meta: { text: 'Next Tab' } as any,
}}
handleComponentDrop={mockOnDropOnTab}
editMode
/>
<Markdown
id="MARKDOWN-1"
parentId="GRID_ID"
parentComponent={{
id: 'GRID_ID',
type: 'GRID',
parents: ['ROOT_ID'],
}}
depth={0}
editMode
index={1}
availableColumnCount={12}
columnWidth={120}
component={{
...props.component,
type: 'MARKDOWN',
id: 'MARKDOWN-1',
meta: { code: 'Dashboard Component' } as any,
}}
logEvent={jest.fn()}
deleteComponent={jest.fn()}
handleComponentDrop={jest.fn()}
onResizeStart={jest.fn()}
onResize={jest.fn()}
onResizeStop={jest.fn()}
updateComponents={jest.fn()}
addDangerToast={jest.fn()}
/>
</>,
{
useRedux: true,
useDnd: true,
},
);
fireEvent.dragStart(screen.getByText('🚀 Aspiring Developers'));
fireEvent.drop(screen.getByText('Next Tab'));
await waitFor(() => expect(mockOnDropOnTab).toHaveBeenCalled());
expect(mockOnDropOnTab).toHaveBeenCalledWith(
expect.objectContaining({
destination: { id: props.parentComponent.id, index: 2, type: 'TABS' },
}),
);
fireEvent.dragStart(screen.getByText('Dashboard Component'));
fireEvent.drop(screen.getByText('Next Tab'));
await waitFor(() => expect(mockOnDropOnTab).toHaveBeenCalledTimes(2));
expect(mockOnDropOnTab).toHaveBeenLastCalledWith(
expect.objectContaining({
destination: {
id: 'TAB-Next-',
index: props.component.children.length,
type: 'TAB',
},
}),
);
});
test('Edit table title', () => { test('Edit table title', () => {
const props = createProps(); const props = createProps();
props.editMode = true; props.editMode = true;

View File

@ -82,7 +82,7 @@ export default function getDropPosition(monitor, Component) {
const siblingDropOrientation = const siblingDropOrientation =
orientation === 'row' ? 'horizontal' : 'vertical'; orientation === 'row' ? 'horizontal' : 'vertical';
if (isDraggingOverShallow && validChild && !validSibling) { if (validChild && !validSibling) {
// easiest case, insert as child // easiest case, insert as child
if (childDropOrientation === 'vertical') { if (childDropOrientation === 'vertical') {
return hasChildren ? DROP_RIGHT : DROP_LEFT; return hasChildren ? DROP_RIGHT : DROP_LEFT;