mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
chore(ts): Migrate Row.jsx to Row.tsx (#36347)
Co-authored-by: Amy Li <amym1734@gmail.com>
This commit is contained in:
@@ -16,17 +16,24 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { fireEvent, render } from 'spec/helpers/testing-library';
|
||||
import React from 'react';
|
||||
import {
|
||||
fireEvent,
|
||||
render,
|
||||
RenderResult,
|
||||
screen,
|
||||
} from 'spec/helpers/testing-library';
|
||||
|
||||
import BackgroundStyleDropdown from 'src/dashboard/components/menu/BackgroundStyleDropdown';
|
||||
import IconButton from 'src/dashboard/components/IconButton';
|
||||
import { DASHBOARD_GRID_ID } from 'src/dashboard/util/constants';
|
||||
|
||||
import { getMockStore } from 'spec/fixtures/mockStore';
|
||||
import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout';
|
||||
import { initialState } from 'src/SqlLab/fixtures';
|
||||
import Row from './Row';
|
||||
|
||||
interface MockIntersectionObserverEntry {
|
||||
isIntersecting: boolean;
|
||||
}
|
||||
|
||||
jest.mock('@superset-ui/core', () => ({
|
||||
...jest.requireActual('@superset-ui/core'),
|
||||
isFeatureEnabled: jest.fn(() => true),
|
||||
@@ -44,47 +51,84 @@ jest.mock('src/dashboard/util/isEmbedded', () => ({
|
||||
}));
|
||||
|
||||
jest.mock('src/dashboard/components/dnd/DragDroppable', () => ({
|
||||
Draggable: ({ children }) => (
|
||||
<div data-test="mock-draggable">{children({})}</div>
|
||||
),
|
||||
Droppable: ({ children, depth }) => (
|
||||
<div data-test="mock-droppable" depth={depth}>
|
||||
Draggable: ({
|
||||
children,
|
||||
}: {
|
||||
children: (args: object) => React.ReactNode;
|
||||
}) => <div data-test="mock-draggable">{children({})}</div>,
|
||||
|
||||
Droppable: ({
|
||||
children,
|
||||
depth,
|
||||
}: {
|
||||
children: (args: object) => React.ReactNode;
|
||||
depth: number;
|
||||
}) => (
|
||||
<div data-test="mock-droppable" data-depth={depth}>
|
||||
{children({})}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
jest.mock(
|
||||
'src/dashboard/containers/DashboardComponent',
|
||||
() =>
|
||||
({ availableColumnCount, depth }) => (
|
||||
<div data-test="mock-dashboard-component" depth={depth}>
|
||||
{availableColumnCount}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
jest.mock(
|
||||
'src/dashboard/components/menu/WithPopoverMenu',
|
||||
() =>
|
||||
({ children }) => <div data-test="mock-with-popover-menu">{children}</div>,
|
||||
);
|
||||
jest.mock('src/dashboard/containers/DashboardComponent', () => {
|
||||
return ({
|
||||
availableColumnCount,
|
||||
depth,
|
||||
}: {
|
||||
availableColumnCount: number;
|
||||
depth: number;
|
||||
}) => (
|
||||
<div data-test="mock-dashboard-component" data-depth={depth}>
|
||||
{availableColumnCount}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
jest.mock(
|
||||
'src/dashboard/components/DeleteComponentButton',
|
||||
() =>
|
||||
({ onDelete }) => (
|
||||
<button
|
||||
type="button"
|
||||
data-test="mock-delete-component-button"
|
||||
onClick={onDelete}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
),
|
||||
);
|
||||
jest.mock('src/dashboard/components/menu/WithPopoverMenu', () => {
|
||||
return ({ children }: { children: React.ReactNode }) => (
|
||||
<div data-test="mock-with-popover-menu">{children}</div>
|
||||
);
|
||||
});
|
||||
|
||||
const rowWithoutChildren = { ...mockLayout.present.ROW_ID, children: [] };
|
||||
const props = {
|
||||
jest.mock('src/dashboard/components/DeleteComponentButton', () => {
|
||||
return ({ onDelete }: { onDelete: () => void }) => (
|
||||
<button
|
||||
type="button"
|
||||
data-test="mock-delete-component-button"
|
||||
onClick={onDelete}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
const rowWithoutChildren = {
|
||||
...mockLayout.present.ROW_ID,
|
||||
children: [],
|
||||
};
|
||||
interface RowTestProps {
|
||||
id: string;
|
||||
parentId: string;
|
||||
component: typeof mockLayout.present.ROW_ID;
|
||||
parentComponent: (typeof mockLayout.present)[typeof DASHBOARD_GRID_ID];
|
||||
index: number;
|
||||
depth: number;
|
||||
editMode: boolean;
|
||||
availableColumnCount: number;
|
||||
columnWidth: number;
|
||||
occupiedColumnCount: number;
|
||||
onResizeStart: () => void;
|
||||
onResize: () => void;
|
||||
onResizeStop: () => void;
|
||||
handleComponentDrop: () => void;
|
||||
deleteComponent: () => void;
|
||||
updateComponents: () => void;
|
||||
isComponentVisible: boolean;
|
||||
maxChildrenHeight: number;
|
||||
onChangeTab: () => void;
|
||||
}
|
||||
|
||||
const props: RowTestProps = {
|
||||
id: 'ROW_ID',
|
||||
parentId: DASHBOARD_GRID_ID,
|
||||
component: mockLayout.present.ROW_ID,
|
||||
@@ -95,15 +139,18 @@ const props = {
|
||||
availableColumnCount: 12,
|
||||
columnWidth: 50,
|
||||
occupiedColumnCount: 6,
|
||||
onResizeStart() {},
|
||||
onResize() {},
|
||||
onResizeStop() {},
|
||||
handleComponentDrop() {},
|
||||
deleteComponent() {},
|
||||
updateComponents() {},
|
||||
onResizeStart: () => {},
|
||||
onResize: () => {},
|
||||
onResizeStop: () => {},
|
||||
handleComponentDrop: () => {},
|
||||
deleteComponent: () => {},
|
||||
updateComponents: () => {},
|
||||
isComponentVisible: true,
|
||||
maxChildrenHeight: 0,
|
||||
onChangeTab: () => {},
|
||||
};
|
||||
|
||||
function setup(overrideProps) {
|
||||
function setup(overrideProps: Partial<RowTestProps> = {}): RenderResult {
|
||||
// We have to wrap provide DragDropContext for the underlying DragDroppable
|
||||
// otherwise we cannot assert on DragDroppable children
|
||||
const mockStore = getMockStore({
|
||||
@@ -153,7 +200,7 @@ test('should render a HoverMenu in editMode', () => {
|
||||
|
||||
// pass the same depth of its droppable area
|
||||
expect(getByTestId('mock-droppable')).toHaveAttribute(
|
||||
'depth',
|
||||
'data-depth',
|
||||
`${props.depth}`,
|
||||
);
|
||||
});
|
||||
@@ -167,17 +214,16 @@ test('should render a DeleteComponentButton in editMode', () => {
|
||||
});
|
||||
|
||||
test.skip('should render a BackgroundStyleDropdown when focused', () => {
|
||||
let wrapper = setup({ component: rowWithoutChildren });
|
||||
expect(wrapper.find(BackgroundStyleDropdown)).toBeFalsy();
|
||||
let { rerender } = setup({ component: rowWithoutChildren });
|
||||
expect(screen.queryByTestId('background-style-dropdown')).toBeFalsy();
|
||||
|
||||
// we cannot set props on the Row because of the WithDragDropContext wrapper
|
||||
wrapper = setup({ component: rowWithoutChildren, editMode: true });
|
||||
wrapper
|
||||
.find(IconButton)
|
||||
.at(1) // first one is delete button
|
||||
.simulate('click');
|
||||
rerender(<Row {...props} component={rowWithoutChildren} editMode={true} />);
|
||||
const buttons = screen.getAllByRole('button');
|
||||
const settingsButton = buttons[1];
|
||||
fireEvent.click(settingsButton);
|
||||
|
||||
expect(wrapper.find(BackgroundStyleDropdown)).toBeTruthy();
|
||||
expect(screen.queryByTestId('background-style-dropdown')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should call deleteComponent when deleted', () => {
|
||||
@@ -190,14 +236,14 @@ test('should call deleteComponent when deleted', () => {
|
||||
test('should pass appropriate availableColumnCount to children', () => {
|
||||
const { getByTestId } = setup();
|
||||
expect(getByTestId('mock-dashboard-component')).toHaveTextContent(
|
||||
props.availableColumnCount - props.occupiedColumnCount,
|
||||
`${props.availableColumnCount - props.occupiedColumnCount}`,
|
||||
);
|
||||
});
|
||||
|
||||
test('should increment the depth of its children', () => {
|
||||
const { getByTestId } = setup();
|
||||
expect(getByTestId('mock-dashboard-component')).toHaveAttribute(
|
||||
'depth',
|
||||
'data-depth',
|
||||
`${props.depth + 1}`,
|
||||
);
|
||||
});
|
||||
@@ -222,7 +268,7 @@ describe('visibility handling for intersection observers', () => {
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
delete window.IntersectionObserver;
|
||||
delete (window as any).IntersectionObserver;
|
||||
});
|
||||
|
||||
test('should handle visibility prop changes without crashing', () => {
|
||||
@@ -261,7 +307,7 @@ describe('visibility handling for intersection observers', () => {
|
||||
});
|
||||
|
||||
test('intersection observer callbacks handle entries without errors', () => {
|
||||
const callback = ([entry]) => {
|
||||
const callback = ([entry]: [MockIntersectionObserverEntry]) => {
|
||||
if (entry.isIntersecting) return true;
|
||||
|
||||
return false;
|
||||
@@ -24,13 +24,17 @@ import {
|
||||
useEffect,
|
||||
useMemo,
|
||||
memo,
|
||||
RefObject,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cx from 'classnames';
|
||||
import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core';
|
||||
import { css, styled } from '@apache-superset/core/ui';
|
||||
import {
|
||||
FeatureFlag,
|
||||
isFeatureEnabled,
|
||||
t,
|
||||
JsonObject,
|
||||
} from '@superset-ui/core';
|
||||
import { css, styled, SupersetTheme } from '@apache-superset/core/ui';
|
||||
import { Icons, Constants } from '@superset-ui/core/components';
|
||||
|
||||
import {
|
||||
Draggable,
|
||||
Droppable,
|
||||
@@ -42,7 +46,6 @@ import HoverMenu from 'src/dashboard/components/menu/HoverMenu';
|
||||
import IconButton from 'src/dashboard/components/IconButton';
|
||||
import BackgroundStyleDropdown from 'src/dashboard/components/menu/BackgroundStyleDropdown';
|
||||
import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu';
|
||||
import { componentShape } from 'src/dashboard/util/propShapes';
|
||||
import backgroundStyleOptions from 'src/dashboard/util/backgroundStyleOptions';
|
||||
import { BACKGROUND_TRANSPARENT } from 'src/dashboard/util/constants';
|
||||
import { isEmbedded } from 'src/dashboard/util/isEmbedded';
|
||||
@@ -50,31 +53,36 @@ import { EMPTY_CONTAINER_Z_INDEX } from 'src/dashboard/constants';
|
||||
import { isCurrentUserBot } from 'src/utils/isBot';
|
||||
import { useDebouncedEffect } from '../../../../explore/exploreUtils';
|
||||
|
||||
const propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
parentId: PropTypes.string.isRequired,
|
||||
component: componentShape.isRequired,
|
||||
parentComponent: componentShape.isRequired,
|
||||
index: PropTypes.number.isRequired,
|
||||
depth: PropTypes.number.isRequired,
|
||||
editMode: PropTypes.bool.isRequired,
|
||||
export type RowProps = {
|
||||
id: string;
|
||||
parentId: string;
|
||||
component: JsonObject;
|
||||
parentComponent: JsonObject;
|
||||
index: number;
|
||||
depth: number;
|
||||
editMode: boolean;
|
||||
|
||||
// grid related
|
||||
availableColumnCount: PropTypes.number.isRequired,
|
||||
columnWidth: PropTypes.number.isRequired,
|
||||
occupiedColumnCount: PropTypes.number.isRequired,
|
||||
onResizeStart: PropTypes.func.isRequired,
|
||||
onResize: PropTypes.func.isRequired,
|
||||
onResizeStop: PropTypes.func.isRequired,
|
||||
maxChildrenHeight: PropTypes.number.isRequired,
|
||||
availableColumnCount: number;
|
||||
columnWidth: number;
|
||||
occupiedColumnCount: number;
|
||||
maxChildrenHeight: number;
|
||||
|
||||
onResizeStart: (e: unknown, direction: unknown) => void;
|
||||
onResize: (e: unknown, direction: unknown, ref: HTMLElement) => void;
|
||||
onResizeStop: (e: unknown, direction: unknown, ref: HTMLElement) => void;
|
||||
|
||||
// dnd
|
||||
handleComponentDrop: PropTypes.func.isRequired,
|
||||
deleteComponent: PropTypes.func.isRequired,
|
||||
updateComponents: PropTypes.func.isRequired,
|
||||
handleComponentDrop: (dropResult: unknown) => void;
|
||||
deleteComponent: (id: string, parentId: string) => void;
|
||||
updateComponents: (updates: Record<string, JsonObject>) => void;
|
||||
|
||||
// visibility
|
||||
isComponentVisible: boolean;
|
||||
onChangeTab: (tabId: string) => void;
|
||||
};
|
||||
|
||||
const GridRow = styled.div`
|
||||
const GridRow = styled.div<{ editMode: boolean }>`
|
||||
${({ theme, editMode }) => css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -119,7 +127,7 @@ const GridRow = styled.div`
|
||||
`}
|
||||
`;
|
||||
|
||||
const emptyRowContentStyles = theme => css`
|
||||
const emptyRowContentStyles = (theme: SupersetTheme) => css`
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -129,7 +137,7 @@ const emptyRowContentStyles = theme => css`
|
||||
color: ${theme.colorTextLabel};
|
||||
`;
|
||||
|
||||
const Row = props => {
|
||||
const Row = memo((props: RowProps) => {
|
||||
const {
|
||||
component: rowComponent,
|
||||
parentComponent,
|
||||
@@ -153,8 +161,8 @@ const Row = props => {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const [isInView, setIsInView] = useState(false);
|
||||
const [hoverMenuHovered, setHoverMenuHovered] = useState(false);
|
||||
const [containerHeight, setContainerHeight] = useState(null);
|
||||
const containerRef = useRef();
|
||||
const [containerHeight, setContainerHeight] = useState<number | null>(null);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const isComponentVisibleRef = useRef(isComponentVisible);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -164,8 +172,8 @@ const Row = props => {
|
||||
// if chart not rendered - render it if it's less than 1 view height away from current viewport
|
||||
// if chart rendered - remove it if it's more than 4 view heights away from current viewport
|
||||
useEffect(() => {
|
||||
let observerEnabler;
|
||||
let observerDisabler;
|
||||
let observerEnabler: IntersectionObserver | undefined;
|
||||
let observerDisabler: IntersectionObserver | undefined;
|
||||
|
||||
if (
|
||||
isFeatureEnabled(FeatureFlag.DashboardVirtualization) &&
|
||||
@@ -219,23 +227,23 @@ const Row = props => {
|
||||
containerRef.current &&
|
||||
updatedHeight !== containerHeight
|
||||
) {
|
||||
setContainerHeight(updatedHeight);
|
||||
setContainerHeight(updatedHeight ?? null);
|
||||
}
|
||||
},
|
||||
Constants.FAST_DEBOUNCE,
|
||||
[editMode, containerHeight],
|
||||
);
|
||||
|
||||
const handleChangeFocus = useCallback(nextFocus => {
|
||||
const handleChangeFocus = useCallback((nextFocus: boolean) => {
|
||||
setIsFocused(Boolean(nextFocus));
|
||||
}, []);
|
||||
|
||||
const handleChangeBackground = useCallback(
|
||||
nextValue => {
|
||||
(nextValue: string) => {
|
||||
const metaKey = 'background';
|
||||
if (nextValue && rowComponent.meta[metaKey] !== nextValue) {
|
||||
if (nextValue && rowComponent.meta?.[metaKey] !== nextValue) {
|
||||
updateComponents({
|
||||
[rowComponent.id]: {
|
||||
[rowComponent.id as string]: {
|
||||
...rowComponent,
|
||||
meta: {
|
||||
...rowComponent.meta,
|
||||
@@ -249,26 +257,30 @@ const Row = props => {
|
||||
);
|
||||
|
||||
const handleDeleteComponent = useCallback(() => {
|
||||
deleteComponent(rowComponent.id, parentId);
|
||||
deleteComponent(rowComponent.id as string, parentId);
|
||||
}, [deleteComponent, rowComponent, parentId]);
|
||||
|
||||
const handleMenuHover = useCallback(hovered => {
|
||||
const { isHovered } = hovered;
|
||||
setHoverMenuHovered(isHovered);
|
||||
const handleMenuHover = useCallback((hover: { isHovered: boolean }) => {
|
||||
setHoverMenuHovered(hover.isHovered);
|
||||
}, []);
|
||||
|
||||
const rowItems = useMemo(
|
||||
() => rowComponent.children || [],
|
||||
const rowItems: string[] = useMemo(
|
||||
() =>
|
||||
Array.isArray(rowComponent.children)
|
||||
? (rowComponent.children as string[])
|
||||
: [],
|
||||
[rowComponent.children],
|
||||
);
|
||||
|
||||
const backgroundStyle = backgroundStyleOptions.find(
|
||||
opt =>
|
||||
opt.value === (rowComponent.meta.background || BACKGROUND_TRANSPARENT),
|
||||
);
|
||||
const backgroundStyle =
|
||||
backgroundStyleOptions.find(
|
||||
opt =>
|
||||
opt.value === (rowComponent.meta?.background ?? BACKGROUND_TRANSPARENT),
|
||||
) ?? backgroundStyleOptions[0];
|
||||
|
||||
const remainColumnCount = availableColumnCount - occupiedColumnCount;
|
||||
const renderChild = useCallback(
|
||||
({ dragSourceRef }) => (
|
||||
({ dragSourceRef }: { dragSourceRef: RefObject<HTMLDivElement> }) => (
|
||||
<WithPopoverMenu
|
||||
isFocused={isFocused}
|
||||
onChangeFocus={handleChangeFocus}
|
||||
@@ -291,7 +303,7 @@ const Row = props => {
|
||||
<DragHandle position="left" />
|
||||
<DeleteComponentButton onDelete={handleDeleteComponent} />
|
||||
<IconButton
|
||||
onClick={handleChangeFocus}
|
||||
onClick={() => handleChangeFocus(true)}
|
||||
icon={<Icons.SettingOutlined iconSize="l" />}
|
||||
/>
|
||||
</HoverMenu>
|
||||
@@ -334,13 +346,13 @@ const Row = props => {
|
||||
...(rowItems.length > 0 && { width: 16 }),
|
||||
}}
|
||||
>
|
||||
{({ dropIndicatorProps }) =>
|
||||
{({ dropIndicatorProps }: { dropIndicatorProps: JsonObject }) =>
|
||||
dropIndicatorProps && <div {...dropIndicatorProps} />
|
||||
}
|
||||
</Droppable>
|
||||
)}
|
||||
{rowItems.length === 0 && (
|
||||
<div css={emptyRowContentStyles}>{t('Empty row')}</div>
|
||||
<div css={emptyRowContentStyles as any}>{t('Empty row')}</div>
|
||||
)}
|
||||
{rowItems.length > 0 &&
|
||||
rowItems.map((componentId, itemIndex) => (
|
||||
@@ -348,7 +360,7 @@ const Row = props => {
|
||||
<DashboardComponent
|
||||
key={componentId}
|
||||
id={componentId}
|
||||
parentId={rowComponent.id}
|
||||
parentId={rowComponent.id as string}
|
||||
depth={depth + 1}
|
||||
index={itemIndex}
|
||||
availableColumnCount={remainColumnCount}
|
||||
@@ -382,9 +394,11 @@ const Row = props => {
|
||||
itemIndex === rowItems.length - 1 && { width: 16 }),
|
||||
}}
|
||||
>
|
||||
{({ dropIndicatorProps }) =>
|
||||
dropIndicatorProps && <div {...dropIndicatorProps} />
|
||||
}
|
||||
{({
|
||||
dropIndicatorProps,
|
||||
}: {
|
||||
dropIndicatorProps: JsonObject;
|
||||
}) => dropIndicatorProps && <div {...dropIndicatorProps} />}
|
||||
</Droppable>
|
||||
)}
|
||||
</Fragment>
|
||||
@@ -431,8 +445,6 @@ const Row = props => {
|
||||
{renderChild}
|
||||
</Draggable>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Row.propTypes = propTypes;
|
||||
|
||||
export default memo(Row);
|
||||
export default Row;
|
||||
@@ -16,6 +16,4 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import Row from './Row';
|
||||
|
||||
export default Row;
|
||||
export { default } from './Row';
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { render } from 'spec/helpers/testing-library';
|
||||
import { render, RenderResult } from 'spec/helpers/testing-library';
|
||||
|
||||
import NewRow from 'src/dashboard/components/gridComponents/new/NewRow';
|
||||
|
||||
@@ -26,12 +26,12 @@ import { ROW_TYPE } from 'src/dashboard/util/componentTypes';
|
||||
jest.mock(
|
||||
'src/dashboard/components/gridComponents/new/DraggableNewComponent',
|
||||
() =>
|
||||
({ type, id }) => (
|
||||
({ type, id }: { type: string; id: string }) => (
|
||||
<div data-test="mock-draggable-new-component">{`${type}:${id}`}</div>
|
||||
),
|
||||
);
|
||||
|
||||
function setup() {
|
||||
function setup(): RenderResult {
|
||||
return render(<NewRow />);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,17 @@ import { Icons } from '@superset-ui/core/components';
|
||||
import { ROW_TYPE } from '../../../util/componentTypes';
|
||||
import { NEW_ROW_ID } from '../../../util/constants';
|
||||
import DraggableNewComponent from './DraggableNewComponent';
|
||||
import { FC } from 'react';
|
||||
|
||||
export default function DraggableNewRow() {
|
||||
return (
|
||||
<DraggableNewComponent
|
||||
id={NEW_ROW_ID}
|
||||
type={ROW_TYPE}
|
||||
label={t('Row')}
|
||||
IconComponent={Icons.ColumnHeightOutlined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
type DraggableNewRowProps = {};
|
||||
|
||||
const DraggableNewRow: FC<DraggableNewRowProps> = () => (
|
||||
<DraggableNewComponent
|
||||
id={NEW_ROW_ID}
|
||||
type={ROW_TYPE}
|
||||
label={t('Row')}
|
||||
IconComponent={Icons.ColumnHeightOutlined}
|
||||
/>
|
||||
);
|
||||
|
||||
export default DraggableNewRow;
|
||||
@@ -49,6 +49,12 @@ const propTypes = {
|
||||
directPathToChild: PropTypes.arrayOf(PropTypes.string),
|
||||
directPathLastUpdated: PropTypes.number,
|
||||
isComponentVisible: PropTypes.bool,
|
||||
availableColumnCount: PropTypes.number,
|
||||
columnWidth: PropTypes.number,
|
||||
onResizeStart: PropTypes.func,
|
||||
onResize: PropTypes.func,
|
||||
onResizeStop: PropTypes.func,
|
||||
isInView: PropTypes.bool,
|
||||
};
|
||||
|
||||
const DashboardComponent = props => {
|
||||
|
||||
Reference in New Issue
Block a user