[SIEM] Fix Timeline registerProvider to be called only when it's needed (#58051)

This commit is contained in:
patrykkopycinski 2020-02-27 22:45:53 +01:00 committed by GitHub
parent 841e64e0c1
commit 2a03dffdad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 40 deletions

View file

@ -12,7 +12,7 @@ import { mockBrowserFields, mocksSource } from '../../containers/source/mock';
import { TestProviders } from '../../mock';
import { mockDataProviders } from '../timeline/data_providers/mock/mock_data_providers';
import { DragDropContextWrapper } from './drag_drop_context_wrapper';
import { DraggableWrapper } from './draggable_wrapper';
import { DraggableWrapper, ConditionalPortal } from './draggable_wrapper';
import { useMountAppended } from '../../utils/use_mount_appended';
describe('DraggableWrapper', () => {
@ -84,3 +84,32 @@ describe('DraggableWrapper', () => {
});
});
});
describe('ConditionalPortal', () => {
const mount = useMountAppended();
const props = {
usePortal: false,
registerProvider: jest.fn(),
isDragging: true,
};
it(`doesn't call registerProvider is NOT isDragging`, () => {
mount(
<ConditionalPortal {...props} isDragging={false}>
<div />
</ConditionalPortal>
);
expect(props.registerProvider.mock.calls.length).toEqual(0);
});
it('calls registerProvider when isDragging', () => {
mount(
<ConditionalPortal {...props}>
<div />
</ConditionalPortal>
);
expect(props.registerProvider.mock.calls.length).toEqual(1);
});
});

View file

@ -4,14 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { createContext, useContext, useEffect } from 'react';
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
import {
Draggable,
DraggableProvided,
DraggableStateSnapshot,
Droppable,
} from 'react-beautiful-dnd';
import { connect, ConnectedProps } from 'react-redux';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
@ -47,34 +47,50 @@ const ProviderContentWrapper = styled.span`
}
`;
type RenderFunctionProp = (
props: DataProvider,
provided: DraggableProvided,
state: DraggableStateSnapshot
) => React.ReactNode;
interface OwnProps {
dataProvider: DataProvider;
inline?: boolean;
render: (
props: DataProvider,
provided: DraggableProvided,
state: DraggableStateSnapshot
) => React.ReactNode;
render: RenderFunctionProp;
truncate?: boolean;
}
type Props = OwnProps & PropsFromRedux;
type Props = OwnProps;
/**
* Wraps a draggable component to handle registration / unregistration of the
* data provider associated with the item being dropped
*/
const DraggableWrapperComponent = React.memo<Props>(
({ dataProvider, registerProvider, render, truncate, unRegisterProvider }) => {
export const DraggableWrapper = React.memo<Props>(
({ dataProvider, render, truncate }) => {
const [providerRegistered, setProviderRegistered] = useState(false);
const dispatch = useDispatch();
const usePortal = useDraggablePortalContext();
useEffect(() => {
registerProvider!({ provider: dataProvider });
return () => {
unRegisterProvider!({ id: dataProvider.id });
};
}, []);
const registerProvider = useCallback(() => {
if (!providerRegistered) {
dispatch(dragAndDropActions.registerProvider({ provider: dataProvider }));
setProviderRegistered(true);
}
}, [dispatch, providerRegistered, dataProvider]);
const unRegisterProvider = useCallback(
() => dispatch(dragAndDropActions.unRegisterProvider({ id: dataProvider.id })),
[dispatch, dataProvider]
);
useEffect(
() => () => {
unRegisterProvider();
},
[]
);
return (
<Wrapper data-test-subj="draggableWrapperDiv">
@ -87,13 +103,18 @@ const DraggableWrapperComponent = React.memo<Props>(
key={getDraggableId(dataProvider.id)}
>
{(provided, snapshot) => (
<ConditionalPortal usePortal={snapshot.isDragging && usePortal}>
<ConditionalPortal
isDragging={snapshot.isDragging}
registerProvider={registerProvider}
usePortal={snapshot.isDragging && usePortal}
>
<ProviderContainer
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
data-test-subj="providerContainer"
isDragging={snapshot.isDragging}
registerProvider={registerProvider}
style={{
...provided.draggableProps.style,
}}
@ -120,28 +141,12 @@ const DraggableWrapperComponent = React.memo<Props>(
</Wrapper>
);
},
(prevProps, nextProps) => {
return (
deepEqual(prevProps.dataProvider, nextProps.dataProvider) &&
prevProps.render !== nextProps.render &&
prevProps.truncate === nextProps.truncate
);
}
(prevProps, nextProps) =>
deepEqual(prevProps.dataProvider, nextProps.dataProvider) &&
prevProps.render !== nextProps.render &&
prevProps.truncate === nextProps.truncate
);
DraggableWrapperComponent.displayName = 'DraggableWrapperComponent';
const mapDispatchToProps = {
registerProvider: dragAndDropActions.registerProvider,
unRegisterProvider: dragAndDropActions.unRegisterProvider,
};
const connector = connect(null, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
export const DraggableWrapper = connector(DraggableWrapperComponent);
DraggableWrapper.displayName = 'DraggableWrapper';
/**
@ -150,8 +155,24 @@ DraggableWrapper.displayName = 'DraggableWrapper';
*
* See: https://github.com/atlassian/react-beautiful-dnd/issues/499
*/
const ConditionalPortal = React.memo<{ children: React.ReactNode; usePortal: boolean }>(
({ children, usePortal }) => (usePortal ? <EuiPortal>{children}</EuiPortal> : <>{children}</>)
interface ConditionalPortalProps {
children: React.ReactNode;
usePortal: boolean;
isDragging: boolean;
registerProvider: () => void;
}
export const ConditionalPortal = React.memo<ConditionalPortalProps>(
({ children, usePortal, registerProvider, isDragging }) => {
useEffect(() => {
if (isDragging) {
registerProvider();
}
}, [isDragging, registerProvider]);
return usePortal ? <EuiPortal>{children}</EuiPortal> : <>{children}</>;
}
);
ConditionalPortal.displayName = 'ConditionalPortal';