2021-05-18 18:29:39 +00:00
|
|
|
import React, { CSSProperties, ReactNode, useCallback, useMemo } from "react";
|
2019-11-13 07:00:25 +00:00
|
|
|
import { BaseStyle } from "widgets/BaseWidget";
|
2021-08-12 05:45:38 +00:00
|
|
|
import { WidgetType, WIDGET_PADDING } from "constants/WidgetConstants";
|
2020-03-27 09:02:11 +00:00
|
|
|
import { generateClassName } from "utils/generators";
|
2020-06-10 17:31:20 +00:00
|
|
|
import styled from "styled-components";
|
2021-08-23 14:12:17 +00:00
|
|
|
import { useClickToSelectWidget } from "utils/hooks/useClickToSelectWidget";
|
2021-08-12 05:45:38 +00:00
|
|
|
import { usePositionedContainerZIndex } from "utils/hooks/usePositionedContainerZIndex";
|
2021-07-26 16:44:10 +00:00
|
|
|
import { useSelector } from "react-redux";
|
2021-09-09 15:10:22 +00:00
|
|
|
import { snipingModeSelector } from "selectors/editorSelectors";
|
|
|
|
|
import WidgetFactory from "utils/WidgetFactory";
|
2022-01-13 13:21:57 +00:00
|
|
|
import { isEqual, memoize } from "lodash";
|
|
|
|
|
import { getReflowSelector } from "selectors/widgetReflowSelectors";
|
|
|
|
|
import { AppState } from "reducers";
|
2020-06-10 17:31:20 +00:00
|
|
|
|
2021-08-12 05:45:38 +00:00
|
|
|
const PositionedWidget = styled.div<{ zIndexOnHover: number }>`
|
2021-06-17 13:26:54 +00:00
|
|
|
&:hover {
|
2021-08-12 05:45:38 +00:00
|
|
|
z-index: ${(props) => props.zIndexOnHover} !important;
|
2021-06-17 13:26:54 +00:00
|
|
|
}
|
|
|
|
|
`;
|
2021-08-12 05:45:38 +00:00
|
|
|
export type PositionedContainerProps = {
|
2019-11-13 07:00:25 +00:00
|
|
|
style: BaseStyle;
|
2020-03-27 09:02:11 +00:00
|
|
|
children: ReactNode;
|
2022-01-13 13:21:57 +00:00
|
|
|
parentId?: string;
|
2020-03-27 09:02:11 +00:00
|
|
|
widgetId: string;
|
2021-08-12 05:45:38 +00:00
|
|
|
widgetType: WidgetType;
|
2021-05-27 06:41:38 +00:00
|
|
|
selected?: boolean;
|
|
|
|
|
focused?: boolean;
|
|
|
|
|
resizeDisabled?: boolean;
|
2019-11-13 07:00:25 +00:00
|
|
|
};
|
|
|
|
|
|
2021-09-09 15:10:22 +00:00
|
|
|
export const checkIsDropTarget = memoize(function isDropTarget(
|
|
|
|
|
type: WidgetType,
|
|
|
|
|
) {
|
|
|
|
|
return !!WidgetFactory.widgetConfigMap.get(type)?.isCanvas;
|
|
|
|
|
});
|
|
|
|
|
|
2021-04-28 10:28:39 +00:00
|
|
|
export function PositionedContainer(props: PositionedContainerProps) {
|
2020-03-04 08:10:40 +00:00
|
|
|
const x = props.style.xPosition + (props.style.xPositionUnit || "px");
|
2020-03-27 09:02:11 +00:00
|
|
|
const y = props.style.yPosition + (props.style.yPositionUnit || "px");
|
|
|
|
|
const padding = WIDGET_PADDING;
|
2021-08-23 14:12:17 +00:00
|
|
|
const clickToSelectWidget = useClickToSelectWidget();
|
2021-07-26 16:44:10 +00:00
|
|
|
const isSnipingMode = useSelector(snipingModeSelector);
|
2021-04-23 05:43:13 +00:00
|
|
|
// memoized classname
|
|
|
|
|
const containerClassName = useMemo(() => {
|
|
|
|
|
return (
|
|
|
|
|
generateClassName(props.widgetId) +
|
|
|
|
|
" positioned-widget " +
|
|
|
|
|
`t--widget-${props.widgetType
|
|
|
|
|
.split("_")
|
|
|
|
|
.join("")
|
|
|
|
|
.toLowerCase()}`
|
|
|
|
|
);
|
|
|
|
|
}, [props.widgetType, props.widgetId]);
|
2021-09-09 15:10:22 +00:00
|
|
|
const isDropTarget = checkIsDropTarget(props.widgetType);
|
|
|
|
|
const { onHoverZIndex, zIndex } = usePositionedContainerZIndex(
|
|
|
|
|
props,
|
|
|
|
|
isDropTarget,
|
|
|
|
|
);
|
2021-08-12 05:45:38 +00:00
|
|
|
|
2022-01-13 13:21:57 +00:00
|
|
|
const reflowSelector = getReflowSelector(props.widgetId);
|
|
|
|
|
|
|
|
|
|
const reflowedPosition = useSelector(reflowSelector, isEqual);
|
|
|
|
|
const dragDetails = useSelector(
|
|
|
|
|
(state: AppState) => state.ui.widgetDragResize.dragDetails,
|
|
|
|
|
);
|
|
|
|
|
const isResizing = useSelector(
|
|
|
|
|
(state: AppState) => state.ui.widgetDragResize.isResizing,
|
|
|
|
|
);
|
|
|
|
|
const isCurrentCanvasReflowing =
|
|
|
|
|
(dragDetails && dragDetails.draggedOn === props.parentId) || isResizing;
|
2021-04-23 05:43:13 +00:00
|
|
|
const containerStyle: CSSProperties = useMemo(() => {
|
2022-01-13 13:21:57 +00:00
|
|
|
const reflowX = reflowedPosition?.X || 0;
|
|
|
|
|
const reflowY = reflowedPosition?.Y || 0;
|
|
|
|
|
const reflowWidth = reflowedPosition?.width;
|
|
|
|
|
const reflowHeight = reflowedPosition?.height;
|
|
|
|
|
const reflowEffected = isCurrentCanvasReflowing && reflowedPosition;
|
|
|
|
|
const hasReflowedPosition = reflowEffected && reflowX + reflowY !== 0;
|
|
|
|
|
const hasReflowedDimensions =
|
|
|
|
|
reflowEffected &&
|
|
|
|
|
((reflowHeight && reflowHeight !== props.style.componentHeight) ||
|
|
|
|
|
(reflowWidth && reflowWidth !== props.style.componentWidth));
|
|
|
|
|
const effectedByReflow = hasReflowedPosition || hasReflowedDimensions;
|
|
|
|
|
const dropTargetStyles: CSSProperties =
|
|
|
|
|
isDropTarget && effectedByReflow ? { pointerEvents: "none" } : {};
|
|
|
|
|
const reflowedPositionStyles: CSSProperties = hasReflowedPosition
|
|
|
|
|
? {
|
|
|
|
|
transform: `translate(${reflowX}px,${reflowY}px)`,
|
|
|
|
|
transition: `transform 100ms linear`,
|
|
|
|
|
boxShadow: `0 0 0 1px rgba(104,113,239,0.5)`,
|
|
|
|
|
}
|
|
|
|
|
: {};
|
|
|
|
|
const reflowDimensionsStyles = hasReflowedDimensions
|
|
|
|
|
? {
|
|
|
|
|
transition: `width 0.1s, height 0.1s`,
|
|
|
|
|
boxShadow: `0 0 0 1px rgba(104,113,239,0.5)`,
|
|
|
|
|
}
|
|
|
|
|
: {};
|
|
|
|
|
const styles: CSSProperties = {
|
2021-04-23 05:43:13 +00:00
|
|
|
position: "absolute",
|
|
|
|
|
left: x,
|
|
|
|
|
top: y,
|
2022-01-13 13:21:57 +00:00
|
|
|
height:
|
|
|
|
|
reflowHeight ||
|
|
|
|
|
props.style.componentHeight + (props.style.heightUnit || "px"),
|
|
|
|
|
width:
|
|
|
|
|
reflowWidth ||
|
|
|
|
|
props.style.componentWidth + (props.style.widthUnit || "px"),
|
2021-04-23 05:43:13 +00:00
|
|
|
padding: padding + "px",
|
2021-08-12 05:45:38 +00:00
|
|
|
zIndex,
|
2021-05-18 18:29:39 +00:00
|
|
|
backgroundColor: "inherit",
|
2022-01-13 13:21:57 +00:00
|
|
|
...reflowedPositionStyles,
|
|
|
|
|
...reflowDimensionsStyles,
|
|
|
|
|
...dropTargetStyles,
|
2021-04-23 05:43:13 +00:00
|
|
|
};
|
2022-01-13 13:21:57 +00:00
|
|
|
return styles;
|
|
|
|
|
}, [
|
|
|
|
|
props.style,
|
|
|
|
|
isCurrentCanvasReflowing,
|
|
|
|
|
onHoverZIndex,
|
|
|
|
|
zIndex,
|
|
|
|
|
reflowSelector,
|
|
|
|
|
reflowedPosition,
|
|
|
|
|
]);
|
2021-04-23 05:43:13 +00:00
|
|
|
|
2021-08-23 14:12:17 +00:00
|
|
|
const onClickFn = useCallback(
|
2021-07-26 16:44:10 +00:00
|
|
|
(e) => {
|
2021-08-23 14:12:17 +00:00
|
|
|
clickToSelectWidget(e, props.widgetId);
|
2021-07-26 16:44:10 +00:00
|
|
|
},
|
2021-08-23 14:12:17 +00:00
|
|
|
[props.widgetId, clickToSelectWidget],
|
2021-07-26 16:44:10 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// TODO: Experimental fix for sniping mode. This should be handled with a single event
|
|
|
|
|
const stopEventPropagation = (e: any) => {
|
|
|
|
|
!isSnipingMode && e.stopPropagation();
|
|
|
|
|
};
|
2021-05-18 18:29:39 +00:00
|
|
|
|
2019-11-13 07:00:25 +00:00
|
|
|
return (
|
2020-06-10 17:31:20 +00:00
|
|
|
<PositionedWidget
|
2021-04-28 10:28:39 +00:00
|
|
|
className={containerClassName}
|
2021-05-18 18:29:39 +00:00
|
|
|
data-testid="test-widget"
|
Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
id={props.widgetId}
|
2021-07-08 06:30:19 +00:00
|
|
|
key={`positioned-container-${props.widgetId}`}
|
2021-05-18 18:29:39 +00:00
|
|
|
// Positioned Widget is the top enclosure for all widgets and clicks on/inside the widget should not be propogated/bubbled out of this Container.
|
2021-08-09 05:35:01 +00:00
|
|
|
onClick={stopEventPropagation}
|
2021-08-23 14:12:17 +00:00
|
|
|
onClickCapture={onClickFn}
|
2020-03-27 09:02:11 +00:00
|
|
|
//Before you remove: This is used by property pane to reference the element
|
2021-04-28 10:28:39 +00:00
|
|
|
style={containerStyle}
|
2021-08-12 05:45:38 +00:00
|
|
|
zIndexOnHover={onHoverZIndex}
|
2019-11-13 07:00:25 +00:00
|
|
|
>
|
|
|
|
|
{props.children}
|
2020-06-10 17:31:20 +00:00
|
|
|
</PositionedWidget>
|
2019-11-13 07:00:25 +00:00
|
|
|
);
|
2021-04-28 10:28:39 +00:00
|
|
|
}
|
2019-11-13 07:00:25 +00:00
|
|
|
|
2020-01-16 11:46:21 +00:00
|
|
|
PositionedContainer.padding = WIDGET_PADDING;
|
2019-11-13 07:00:25 +00:00
|
|
|
|
|
|
|
|
export default PositionedContainer;
|