mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-06 06:48:21 +00:00
Merge pull request #12090 from ToolJet/fix/auto-scroll-component
Fix: Scroll and bring the component in view port
This commit is contained in:
commit
21fd97e290
5 changed files with 114 additions and 22 deletions
|
|
@ -9,6 +9,7 @@ const useCallbackActions = () => {
|
|||
const currentPageComponents = useStore((state) => state?.getCurrentPageComponents(), shallow);
|
||||
const shouldFreeze = useStore((state) => state.getShouldFreeze());
|
||||
const runQuery = useStore((state) => state.queryPanel.runQuery);
|
||||
const getComponentIdToAutoScroll = useStore((state) => state.getComponentIdToAutoScroll);
|
||||
|
||||
const handleRemoveComponent = (component) => {
|
||||
deleteComponents([component.id]);
|
||||
|
|
@ -30,30 +31,22 @@ const useCallbackActions = () => {
|
|||
return toast.success('Copied to the clipboard', { position: 'top-center' });
|
||||
};
|
||||
|
||||
const autoScrollTo = (id) => {
|
||||
setSelectedComponents([id]);
|
||||
const target = document.getElementById(id);
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
};
|
||||
|
||||
const handleAutoScrollToComponent = (data) => {
|
||||
const currentPageComponents = useStore.getState().getCurrentPageComponents();
|
||||
const component = currentPageComponents?.[data.id];
|
||||
|
||||
let parentId = component?.component?.parent;
|
||||
if (parentId) {
|
||||
const regex = /-\d+$/;
|
||||
if (regex.test(parentId)) {
|
||||
parentId = parentId.replace(regex, ''); // To get parentId without tab index if parent type is Tab
|
||||
}
|
||||
const parentType = currentPageComponents?.[parentId]?.component?.component;
|
||||
if (parentType && (parentType === 'Modal' || parentType === 'Tabs')) {
|
||||
autoScrollTo(parentId); // To scroll to parent component if parent type is Modal or Tabs
|
||||
return;
|
||||
}
|
||||
const { isAccessible, computedComponentId, isOnCanvas } = getComponentIdToAutoScroll(data.id);
|
||||
if (!isAccessible) {
|
||||
if (isOnCanvas) {
|
||||
toast.success(
|
||||
`This component can't be opened because it's on the main canvas. Close ${computedComponentId} and click "Go to component" to view it there`
|
||||
);
|
||||
} else
|
||||
toast.success(
|
||||
`This component can't be opened because it's inside ${computedComponentId}. Open ${computedComponentId} and click "Go to component"to view it.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
autoScrollTo(data.id);
|
||||
setSelectedComponents([computedComponentId]);
|
||||
const target = document.getElementById(computedComponentId);
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
};
|
||||
|
||||
const callbackActions = [
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ export function KanbanBoard({ widgetHeight, kanbanProps, parentRef, id }) {
|
|||
const [containers, setContainers] = useState([]);
|
||||
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const setModalOpenOnCanvas = useStore((state) => state.setModalOpenOnCanvas);
|
||||
const [activeId, setActiveId] = useState(null);
|
||||
const cardMovementRef = useRef(null);
|
||||
const shouldUpdateData = useRef(false);
|
||||
|
|
@ -117,6 +118,7 @@ export function KanbanBoard({ widgetHeight, kanbanProps, parentRef, id }) {
|
|||
}
|
||||
/**** End - Logic to reduce the zIndex of modal control box ****/
|
||||
}
|
||||
setModalOpenOnCanvas(`${id}-modal`, showModal);
|
||||
}, [showModal]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export const Modal = function Modal({
|
|||
const size = properties.size ?? 'lg';
|
||||
const [modalWidth, setModalWidth] = useState();
|
||||
const mode = useStore((state) => state.currentMode, shallow);
|
||||
const setModalOpenOnCanvas = useStore((state) => state.setModalOpenOnCanvas);
|
||||
|
||||
/**** Start - Logic to reset the zIndex of modal control box ****/
|
||||
useEffect(() => {
|
||||
|
|
@ -63,6 +64,7 @@ export const Modal = function Modal({
|
|||
useGridStore.getState().actions.setOpenModalWidgetId(null);
|
||||
}
|
||||
}
|
||||
setModalOpenOnCanvas(id, showModal);
|
||||
}, [showModal, id, mode]);
|
||||
/**** End - Logic to reset the zIndex of modal control box ****/
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const initialState = {
|
|||
currentPageHandle: null,
|
||||
showWidgetDeleteConfirmation: false,
|
||||
focusedParentId: null,
|
||||
modalsOpenOnCanvas: [],
|
||||
};
|
||||
|
||||
export const createComponentsSlice = (set, get) => ({
|
||||
|
|
@ -1867,4 +1868,17 @@ export const createComponentsSlice = (set, get) => ({
|
|||
const currentPage = getCurrentPage(moduleId);
|
||||
return currentPage?.autoComputeLayout;
|
||||
},
|
||||
setModalOpenOnCanvas: (modalId, isOpen) => {
|
||||
const { modalsOpenOnCanvas } = get();
|
||||
let newModalOpenOnCanvas = [];
|
||||
|
||||
if (isOpen) {
|
||||
newModalOpenOnCanvas = [...modalsOpenOnCanvas, modalId];
|
||||
} else {
|
||||
newModalOpenOnCanvas = modalsOpenOnCanvas.filter((id) => id !== modalId);
|
||||
}
|
||||
set((state) => {
|
||||
state.modalsOpenOnCanvas = newModalOpenOnCanvas;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,4 +37,85 @@ export const createLeftSideBarSlice = (set, get) => ({
|
|||
toggleLeftSidebar(true);
|
||||
}
|
||||
},
|
||||
getComponentIdToAutoScroll: (componentId) => {
|
||||
const { getCurrentPageComponents, getAllExposedValues, modalsOpenOnCanvas } = get();
|
||||
const currentPageComponents = getCurrentPageComponents();
|
||||
|
||||
let targetComponentId = componentId;
|
||||
let current = componentId;
|
||||
const visited = new Set();
|
||||
let isInsideOpenModal = false;
|
||||
|
||||
// Bubble up to the outermost parent to find the target component
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
if (visited.has(current)) break;
|
||||
visited.add(current);
|
||||
|
||||
const parentId = currentPageComponents?.[current]?.component?.parent;
|
||||
if (!parentId) break;
|
||||
|
||||
let isComponentVisibleInParent = true;
|
||||
let nextPossibleCandidate = parentId;
|
||||
|
||||
// If the component exists inside a tab component
|
||||
const regForTabs = /-(?!\d{12}$)\d+$/; // Parent id for tabs follow the format 'id-index' and index is not UUIDv4 id segment
|
||||
if (regForTabs.test(parentId)) {
|
||||
const reg = /-(\d+)$/;
|
||||
const tabIndex = Number(parentId.match(reg)[1]); // Tab index inside which the component exists
|
||||
|
||||
const tabId = parentId.replace(regForTabs, ''); // Extract tab id from parent id
|
||||
|
||||
const { currentTab } = getAllExposedValues().components?.[tabId] || {};
|
||||
const activeTabIndex = Number(currentTab);
|
||||
|
||||
nextPossibleCandidate = tabId;
|
||||
if (tabIndex !== activeTabIndex) {
|
||||
isComponentVisibleInParent = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the component exists inside a modal component
|
||||
if (currentPageComponents?.[parentId]?.component?.component === 'Modal') {
|
||||
nextPossibleCandidate = parentId;
|
||||
if (!modalsOpenOnCanvas.includes(parentId)) {
|
||||
isComponentVisibleInParent = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the component exists inside the kanban component's modal
|
||||
if (parentId.endsWith('-modal')) {
|
||||
nextPossibleCandidate = parentId.replace(/-modal$/, ''); // Extract kanban id from parent id
|
||||
if (!modalsOpenOnCanvas.includes(parentId)) {
|
||||
isComponentVisibleInParent = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the open modal contains the component
|
||||
if (modalsOpenOnCanvas[modalsOpenOnCanvas.length - 1] === parentId) {
|
||||
isInsideOpenModal = true;
|
||||
}
|
||||
|
||||
if (!isComponentVisibleInParent) {
|
||||
targetComponentId = nextPossibleCandidate;
|
||||
}
|
||||
current = nextPossibleCandidate;
|
||||
}
|
||||
|
||||
if (modalsOpenOnCanvas.length > 0 && !isInsideOpenModal) {
|
||||
const targetId = visited.size === 1 ? modalsOpenOnCanvas[modalsOpenOnCanvas.length - 1] : current;
|
||||
const componentName = currentPageComponents?.[targetId]?.component?.name;
|
||||
|
||||
return {
|
||||
isAccessible: false,
|
||||
computedComponentId: componentName,
|
||||
isOnCanvas: visited.size === 1,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isAccessible: true,
|
||||
computedComponentId: targetComponentId,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue