mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
Merge branch 'appbuilder/sprint-10' of https://github.com/ToolJet/ToolJet into appbuilder/sprint-10
This commit is contained in:
commit
32f8093428
10 changed files with 143 additions and 55 deletions
|
|
@ -48,7 +48,6 @@ export const ConfigHandle = ({
|
|||
}, shallow);
|
||||
|
||||
let height = visibility === false ? 10 : widgetHeight;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`config-handle ${customClassName}`}
|
||||
|
|
@ -60,7 +59,7 @@ export const ConfigHandle = ({
|
|||
: position === 'top'
|
||||
? '-20px'
|
||||
: `${height - (CONFIG_HANDLE_HEIGHT + BUFFER_HEIGHT)}px`,
|
||||
visibility: _showHandle ? 'visible' : 'hidden',
|
||||
visibility: _showHandle || visibility === false ? 'visible' : 'hidden',
|
||||
left: '-1px',
|
||||
}}
|
||||
onClick={(e) => {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ import {
|
|||
handleDeactivateTargets,
|
||||
handleActivateNonDraggingComponents,
|
||||
} from './gridUtils';
|
||||
import { useAppVersionStore } from '@/_stores/appVersionStore';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
import { dragContextBuilder, getAdjustedDropPosition } from './helpers/dragEnd';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import './Grid.css';
|
||||
|
|
@ -67,6 +65,8 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
const prevDragParentId = useRef(null);
|
||||
const newDragParentId = useRef(null);
|
||||
const [isGroupDragging, setIsGroupDragging] = useState(false);
|
||||
const checkIfAnyWidgetVisibilityChanged = useStore((state) => state.checkIfAnyWidgetVisibilityChanged(), shallow);
|
||||
const getExposedValueOfComponent = useStore((state) => state.getExposedValueOfComponent, shallow);
|
||||
const setReorderContainerChildren = useStore((state) => state.setReorderContainerChildren, shallow);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -319,7 +319,7 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
useEffect(() => {
|
||||
reloadGrid();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedComponents, openModalWidgetId, boxList, currentLayout]);
|
||||
}, [selectedComponents, openModalWidgetId, boxList, currentLayout, checkIfAnyWidgetVisibilityChanged]);
|
||||
|
||||
const updateNewPosition = (events, parent = null) => {
|
||||
const posWithParent = {
|
||||
|
|
@ -331,6 +331,8 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
|
||||
const isComponentVisible = (id) => {
|
||||
const component = getResolvedComponent(id);
|
||||
const componentExposedVisibility = getExposedValueOfComponent(id)?.isVisible;
|
||||
if (componentExposedVisibility === false) return false;
|
||||
let visibility;
|
||||
if (isArray(component)) {
|
||||
visibility = component?.[0]?.properties?.visibility ?? component?.[0]?.styles?.visibility ?? null;
|
||||
|
|
@ -633,13 +635,13 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
// When clicked on widget boundary/resizer, select the component
|
||||
setSelectedComponents([e.target.id]);
|
||||
}
|
||||
showGridLines();
|
||||
if (!isComponentVisible(e.target.id)) {
|
||||
return false;
|
||||
}
|
||||
handleActivateNonDraggingComponents();
|
||||
useGridStore.getState().actions.setResizingComponentId(e.target.id);
|
||||
e.setMin([gridWidth, GRID_HEIGHT]);
|
||||
showGridLines();
|
||||
}}
|
||||
onResizeEnd={(e) => {
|
||||
try {
|
||||
|
|
@ -648,10 +650,12 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
return id === e.target.id;
|
||||
});
|
||||
hideGridLines();
|
||||
if (!e.lastEvent) {
|
||||
return;
|
||||
}
|
||||
let _gridWidth = useGridStore.getState().subContainerWidths[currentWidget.component?.parent] || gridWidth;
|
||||
let width = Math.round(e?.lastEvent?.width / _gridWidth) * _gridWidth;
|
||||
const height = Math.round(e?.lastEvent?.height / GRID_HEIGHT) * GRID_HEIGHT;
|
||||
|
||||
const currentWidth = currentWidget.width * _gridWidth;
|
||||
const diffWidth = e.lastEvent?.width - currentWidth;
|
||||
const diffHeight = e.lastEvent?.height - currentWidget?.height;
|
||||
|
|
@ -882,7 +886,6 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
|
||||
left = dragged.left * sourcegridWidth;
|
||||
top = dragged.top;
|
||||
|
||||
!isModalToCanvas ??
|
||||
toast.error(`${dragged.widgetType} is not compatible as a child component of ${target.widgetType}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { renderTooltip } from '@/_helpers/appUtils';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import ErrorBoundary from '@/_ui/ErrorBoundary';
|
||||
import { BOX_PADDING } from './appCanvasConstants';
|
||||
|
||||
const shouldAddBoxShadowAndVisibility = [
|
||||
'Table',
|
||||
'TextInput',
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ const WidgetWrapper = memo(
|
|||
});
|
||||
const visibility = useStore((state) => {
|
||||
const component = state.getResolvedComponent(id, subContainerIndex);
|
||||
const componentExposedVisibility = state.getExposedValueOfComponent(id)?.isVisible;
|
||||
if (componentExposedVisibility === false) return false;
|
||||
if (component?.properties?.visibility === false || component?.styles?.visibility === false) return false;
|
||||
return true;
|
||||
});
|
||||
|
|
@ -52,7 +54,7 @@ const WidgetWrapper = memo(
|
|||
height: visibility === false ? '10px' : `${height}px`,
|
||||
transform: `translate(${layoutData.left * gridWidth}px, ${layoutData.top}px)`,
|
||||
WebkitFontSmoothing: 'antialiased',
|
||||
border: visibility === false ? `1px solid var(--border-default)` : 'none',
|
||||
border: visibility === false && mode === 'edit' ? `1px solid var(--border-default)` : 'none',
|
||||
};
|
||||
|
||||
if (!componentType) return null;
|
||||
|
|
|
|||
|
|
@ -49,8 +49,16 @@ export const addNewWidgetToTheEditor = (componentType, eventMonitorObject, curre
|
|||
left = Math.round(left / gridWidth);
|
||||
// Adjust widget width based on the dropping canvas width
|
||||
const mainCanvasWidth = useGridStore.getState().subContainerWidths['canvas'];
|
||||
const width = Math.round((defaultWidth * mainCanvasWidth) / gridWidth);
|
||||
let width = Math.round((defaultWidth * mainCanvasWidth) / gridWidth);
|
||||
|
||||
// Ensure minimum width
|
||||
width = Math.max(width, 1);
|
||||
|
||||
// Adjust position and width if exceeding grid bounds
|
||||
if (width + left > NO_OF_GRIDS) {
|
||||
left = Math.max(0, NO_OF_GRIDS - width);
|
||||
width = Math.min(width, NO_OF_GRIDS);
|
||||
}
|
||||
if (currentLayout === 'mobile') {
|
||||
componentData.definition.others.showOnDesktop.value = `{{false}}`;
|
||||
componentData.definition.others.showOnMobile.value = `{{true}}`;
|
||||
|
|
@ -513,7 +521,7 @@ export function pasteComponents(targetParentId, copiedComponentObj) {
|
|||
targetParentId === key ||
|
||||
(components?.[key]?.component.component === 'Tabs' &&
|
||||
targetParentId?.split('-')?.slice(0, -1)?.join('-') === key) ||
|
||||
(['Container', 'Form', 'Modal'].includes(components?.[key]?.component.component) &&
|
||||
(['Container', 'Form', 'ModalV2'].includes(components?.[key]?.component.component) &&
|
||||
['header', 'footer'].some((section) => targetParentId.includes(section)))
|
||||
)
|
||||
) {
|
||||
|
|
@ -525,6 +533,7 @@ export function pasteComponents(targetParentId, copiedComponentObj) {
|
|||
}
|
||||
|
||||
pastedComponents.forEach((component) => {
|
||||
component = deepClone(component);
|
||||
const newComponentId = isCut ? component.id : uuidv4();
|
||||
const componentName = computeComponentName(component.component.component, {
|
||||
...components,
|
||||
|
|
@ -565,15 +574,28 @@ export function pasteComponents(targetParentId, copiedComponentObj) {
|
|||
componentData.definition.others.showOnMobile.value = currentLayout === 'mobile' ? `{{true}}` : `{{false}}`;
|
||||
|
||||
// Adjust width if parent changed
|
||||
let width = component.layouts.desktop.width;
|
||||
let width = component.layouts[currentLayout].width;
|
||||
|
||||
if (targetParentId !== component.component?.parent) {
|
||||
const containerWidth = useGridStore.getState().subContainerWidths[targetParentId || 'canvas'];
|
||||
const oldContainerWidth = useGridStore.getState().subContainerWidths[component?.component?.parent || 'canvas'];
|
||||
width = Math.round((width * oldContainerWidth) / containerWidth);
|
||||
|
||||
// Ensure minimum width
|
||||
width = Math.max(width, 1);
|
||||
|
||||
// Adjust position and width if exceeding grid bounds
|
||||
if (width + component.layouts[currentLayout].left > NO_OF_GRIDS) {
|
||||
component.layouts[currentLayout].left = Math.max(0, NO_OF_GRIDS - width);
|
||||
width = Math.min(width, NO_OF_GRIDS);
|
||||
}
|
||||
}
|
||||
|
||||
component.layouts[currentLayout].width = width;
|
||||
component.layouts[currentLayout] = {
|
||||
...component.layouts[currentLayout],
|
||||
width,
|
||||
};
|
||||
|
||||
const newComponent = {
|
||||
component: {
|
||||
...componentData,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.active-target {
|
||||
outline: 1px solid #4af;
|
||||
outline: 1px solid #4af !important;
|
||||
}
|
||||
|
||||
.main-editor-canvas .widget-target:not(:has(.widget-target:hover)):hover {
|
||||
|
|
|
|||
|
|
@ -42,12 +42,18 @@ const CustomDragLayer = ({ size }) => {
|
|||
const canvasBounds = item?.canvasRef?.getBoundingClientRect();
|
||||
const height = size.height;
|
||||
|
||||
const width = (canvasWidth * size.width) / NO_OF_GRIDS;
|
||||
const mainCanvasWidth = document.getElementById('real-canvas')?.offsetWidth || 0;
|
||||
|
||||
let width = (mainCanvasWidth * size.width) / NO_OF_GRIDS;
|
||||
// Calculate position relative to the current canvas (parent or child)
|
||||
const left = currentOffset.x - (canvasBounds?.left || 0);
|
||||
const top = currentOffset.y - (canvasBounds?.top || 0);
|
||||
|
||||
// Adjust position and width if exceeding grid bounds
|
||||
if (width >= canvasWidth) {
|
||||
width = canvasWidth;
|
||||
}
|
||||
|
||||
const [x, y] = snapToGrid(canvasWidth, left, top);
|
||||
return (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -68,6 +68,54 @@ export const Modal = function Modal({
|
|||
}, [showModal, id, mode]);
|
||||
/**** End - Logic to reset the zIndex of modal control box ****/
|
||||
|
||||
// Side effects for modal, which include dom manipulation to hide overflow when opening
|
||||
// And cleaning up dom when modal is closed
|
||||
|
||||
const onShowSideEffects = () => {
|
||||
const canvasElement = document.querySelector('.page-container.canvas-container');
|
||||
const realCanvasEl = document.getElementsByClassName('real-canvas')[0];
|
||||
const allModalContainers = realCanvasEl.querySelectorAll('.modal');
|
||||
const modalContainer = allModalContainers[allModalContainers.length - 1];
|
||||
|
||||
if (canvasElement && realCanvasEl && modalContainer) {
|
||||
const currentScroll = canvasElement.scrollTop;
|
||||
canvasElement.style.overflowY = 'hidden';
|
||||
|
||||
modalContainer.style.height = `${canvasElement.offsetHeight}px`;
|
||||
modalContainer.style.top = `${currentScroll}px`;
|
||||
fireEvent('onOpen');
|
||||
}
|
||||
};
|
||||
|
||||
const onHideSideEffects = () => {
|
||||
const canvasElement = document.querySelector('.page-container.canvas-container');
|
||||
const realCanvasEl = document.getElementsByClassName('real-canvas')[0];
|
||||
const allModalContainers = realCanvasEl.querySelectorAll('.modal');
|
||||
const modalContainer = allModalContainers[allModalContainers.length - 1];
|
||||
const hasManyModalsOpen = allModalContainers.length > 1;
|
||||
|
||||
if (canvasElement && realCanvasEl && modalContainer) {
|
||||
modalContainer.style.height = ``;
|
||||
modalContainer.style.top = ``;
|
||||
fireEvent('onClose');
|
||||
}
|
||||
if (canvasElement && !hasManyModalsOpen) {
|
||||
canvasElement.style.overflow = 'auto';
|
||||
}
|
||||
};
|
||||
|
||||
// useEventListener('resize', onShowSideEffects, window);
|
||||
|
||||
const onShowModal = () => {
|
||||
openModal();
|
||||
onShowSideEffects();
|
||||
};
|
||||
|
||||
const onHideModal = () => {
|
||||
onHideSideEffects();
|
||||
hideModal();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const exposedVariables = {
|
||||
open: async function () {
|
||||
|
|
@ -93,58 +141,48 @@ export const Modal = function Modal({
|
|||
setShowModal(true);
|
||||
}
|
||||
|
||||
// Add debounced version of handleModalOpen
|
||||
const debouncedModalOpen = debounce(() => {
|
||||
onShowSideEffects();
|
||||
}, 10);
|
||||
|
||||
useEffect(() => {
|
||||
const handleModalOpen = () => {
|
||||
openModal();
|
||||
const canvasElement = document.getElementsByClassName('canvas-container')[0];
|
||||
const modalBackdropEl = document.getElementsByClassName('modal-backdrop')[0];
|
||||
const realCanvasEl = document.getElementsByClassName('real-canvas')[0];
|
||||
const modalCanvasEl = document.getElementById(`canvas-${id}`);
|
||||
if (canvasElement && modalBackdropEl && modalCanvasEl && realCanvasEl) {
|
||||
realCanvasEl.style.height = '100vh';
|
||||
realCanvasEl.style.position = 'absolute';
|
||||
realCanvasEl.style.overflow = 'hidden';
|
||||
// Select the DOM element
|
||||
const canvasElement = document.querySelector('.page-container.canvas-container');
|
||||
|
||||
modalBackdropEl.style.height = '100vh';
|
||||
modalBackdropEl.style.minHeight = '100vh';
|
||||
modalBackdropEl.style.minHeight = '100vh';
|
||||
modalCanvasEl.style.height = modalHeight;
|
||||
}
|
||||
if (!canvasElement) return; // Ensure the element exists
|
||||
|
||||
// Create a ResizeObserver
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
debouncedModalOpen();
|
||||
});
|
||||
|
||||
// Observe the canvas element
|
||||
resizeObserver.observe(canvasElement);
|
||||
|
||||
return () => {
|
||||
// Cleanup observer on component unmount
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Add debounced version of handleModalOpen
|
||||
const debouncedModalOpen = debounce(() => {
|
||||
handleModalOpen();
|
||||
}, 10);
|
||||
|
||||
const handleModalClose = () => {
|
||||
const canvasElement = document.getElementsByClassName('canvas-container')[0];
|
||||
const realCanvasEl = document.getElementsByClassName('real-canvas')[0];
|
||||
const canvasHeight = realCanvasEl?.getAttribute('canvas-height');
|
||||
|
||||
if (canvasElement && realCanvasEl && canvasHeight) {
|
||||
realCanvasEl.style.height = canvasHeight;
|
||||
realCanvasEl.style.position = '';
|
||||
|
||||
realCanvasEl.style.overflow = 'auto';
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (showModal) {
|
||||
debouncedModalOpen();
|
||||
} else {
|
||||
// if (document.getElementsByClassName('modal-content')[0] == undefined) {
|
||||
handleModalClose();
|
||||
// }
|
||||
if (document.getElementsByClassName('modal-content')[0] == undefined) {
|
||||
onHideModal();
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup the effect
|
||||
return () => {
|
||||
if (document.getElementsByClassName('modal-content')[0] == undefined) {
|
||||
handleModalClose();
|
||||
onHideModal();
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showModal, modalHeight]);
|
||||
}, [modalHeight, size]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) {
|
||||
|
|
@ -245,7 +283,9 @@ export const Modal = function Modal({
|
|||
keyboard={true}
|
||||
enforceFocus={false}
|
||||
animation={false}
|
||||
onEscapeKeyDown={() => hideOnEsc && hideModal()}
|
||||
onShow={() => onShowModal()}
|
||||
onHide={() => onHideModal()}
|
||||
onEscapeKeyDown={() => hideOnEsc && onHideModal()}
|
||||
id="modal-container"
|
||||
component-id={id}
|
||||
backdrop={'static'}
|
||||
|
|
@ -258,7 +298,7 @@ export const Modal = function Modal({
|
|||
titleAlignment,
|
||||
hideTitleBar,
|
||||
hideCloseButton,
|
||||
hideModal,
|
||||
hideModal: onHideModal,
|
||||
component,
|
||||
showConfigHandler: mode === 'edit',
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ export const MarkdownColumn = ({
|
|||
className={`h-100 text-container long-text-input d-flex${
|
||||
darkMode ? ' textarea-dark-theme' : ''
|
||||
} justify-content-${determineJustifyContentValue(horizontalAlignment)}`}
|
||||
tabIndex={-1}
|
||||
style={{
|
||||
color: cellTextColor ? cellTextColor : 'inherit',
|
||||
outline: 'none',
|
||||
|
|
|
|||
|
|
@ -77,6 +77,22 @@ export const createGridSlice = (set, get) => ({
|
|||
setLastCanvasClickPosition: (position) => {
|
||||
set({ lastCanvasClickPosition: position });
|
||||
},
|
||||
checkIfAnyWidgetVisibilityChanged: () => {
|
||||
// This is required to reload the grid if visibility is turned off using CSA
|
||||
const { getExposedValueOfComponent, getCurrentPageComponents } = get();
|
||||
const currentPageComponents = getCurrentPageComponents();
|
||||
|
||||
const visibilityState = {};
|
||||
|
||||
Object.keys(currentPageComponents).forEach((componentId) => {
|
||||
const componentExposedVisibility = getExposedValueOfComponent(componentId)?.isVisible;
|
||||
|
||||
// Determine if component is visible
|
||||
visibilityState[componentId] = !(componentExposedVisibility === false);
|
||||
});
|
||||
|
||||
return visibilityState;
|
||||
},
|
||||
setReorderContainerChildren: (containerId) => {
|
||||
// Function to trigger reordering of specific container for tab navigation
|
||||
set((state) => ({
|
||||
|
|
|
|||
Loading…
Reference in a new issue