From 550feae6b59c76d036286527c3ee1a1d35511164 Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Thu, 27 Feb 2025 23:59:12 +0530 Subject: [PATCH 01/53] Fixed issue where the search text was not getting highlighted correctly and added shortcut for find previous match. --- .../src/AppBuilder/CodeEditor/SearchBox.jsx | 27 +++++++++++++++++-- .../src/AppBuilder/CodeEditor/styles.scss | 4 ++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx b/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx index 2b807f718b..28f7451b95 100644 --- a/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx @@ -1,3 +1,4 @@ +/* eslint-disable import/no-unresolved */ import React, { useEffect, useState } from 'react'; import { createRoot } from 'react-dom/client'; import { @@ -9,12 +10,13 @@ import { replaceNext, replaceAll, openSearchPanel, - // eslint-disable-next-line import/no-unresolved } from '@codemirror/search'; import './SearchBox.scss'; import InputComponent from '@/components/ui/Input/Index.jsx'; import { Button as ButtonComponent } from '@/components/ui/Button/Button.jsx'; import { ToolTip } from '@/_components/ToolTip'; +import { SelectionRange } from '@codemirror/state'; +import { useHotkeys } from 'react-hotkeys-hook'; export const handleSearchPanel = (view) => { const dom = document.createElement('div'); @@ -35,6 +37,11 @@ function SearchPanel({ view }) { replace: replaceTerm, }); view.dispatch({ effects: setSearchQuery.of(query) }); + + const currentPos = view.state.selection.main.head; + view.dispatch({ + selection: SelectionRange.create(currentPos, currentPos), + }); }; useEffect(() => { @@ -44,12 +51,28 @@ function SearchPanel({ view }) { return () => clearTimeout(handler); }, [searchText, replaceText]); + const [shortcutEnabled, setShortcutEnabled] = useState(false); + + // Shortcuts for search input field + useHotkeys( + ['shift+enter', 'enter'], + (event, handler) => { + if (handler.shift && handler.keys[0] === 'enter') findPrevious(view); + else if (handler.keys[0] === 'enter') findNext(view); + }, + { + enabled: shortcutEnabled, + enableOnFormTags: true, + } + ); + const displaySearchField = () => (
setSearchText(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && findNext(view)} + onFocus={() => setShortcutEnabled(true)} + onBlur={() => setShortcutEnabled(false)} placeholder="Find" size="small" value={searchText} diff --git a/frontend/src/AppBuilder/CodeEditor/styles.scss b/frontend/src/AppBuilder/CodeEditor/styles.scss index c646fd30b1..6c8e114871 100644 --- a/frontend/src/AppBuilder/CodeEditor/styles.scss +++ b/frontend/src/AppBuilder/CodeEditor/styles.scss @@ -644,11 +644,13 @@ } .cm-searchMatch { + background-color: #F9E71A !important; + .cm-selectionMatch { background-color: #F9E71A !important; } } .cm-searchMatch.cm-searchMatch-selected { - background-color: #F28F2D; + background-color: #F28F2D !important; } \ No newline at end of file From 5a1427e2e426d05d1c958c5de1e0554b429c608a Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Fri, 28 Feb 2025 01:48:53 +0530 Subject: [PATCH 02/53] Added auto scroll functionality if the component list is long in inspector. --- .../LeftSidebarInspector/LeftSidebarInspector.jsx | 14 ++++++++++++-- frontend/src/_ui/JSONTreeViewer/JSONNode.jsx | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/LeftSidebarInspector.jsx b/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/LeftSidebarInspector.jsx index dc4b2cf7af..3adca4be98 100644 --- a/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/LeftSidebarInspector.jsx +++ b/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/LeftSidebarInspector.jsx @@ -88,9 +88,19 @@ const LeftSidebarInspector = ({ darkMode, pinned, setPinned }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [sortedComponents, sortedQueries, sortedVariables, sortedConstants, sortedPageVariables, sortedGlobalVariables]); - const handleNodeExpansion = (path) => { + const handleNodeExpansion = (path, data, currentNode) => { if (pathToBeInspected && path?.length > 0) { - return pathToBeInspected.includes(path[path.length - 1]); + const shouldExpand = pathToBeInspected.includes(path[path.length - 1]); + + // Scroll to the component in the inspector + if (path?.length === 2 && path?.[0] === 'components' && shouldExpand) { + const target = document.getElementById(`inspector-node-${String(currentNode).toLowerCase()}`); + if (target) { + target.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + } + + return shouldExpand; } else return false; }; diff --git a/frontend/src/_ui/JSONTreeViewer/JSONNode.jsx b/frontend/src/_ui/JSONTreeViewer/JSONNode.jsx index 65a4ece91d..8913dbb277 100644 --- a/frontend/src/_ui/JSONTreeViewer/JSONNode.jsx +++ b/frontend/src/_ui/JSONTreeViewer/JSONNode.jsx @@ -53,7 +53,7 @@ export const JSONNode = ({ data, ...restProps }) => { React.useEffect(() => { if (typeof shouldExpandNode === 'function') { - set(shouldExpandNode(path, data)); + set(shouldExpandNode(path, data, currentNode)); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [pathToBeInspected]); @@ -337,6 +337,7 @@ export const JSONNode = ({ data, ...restProps }) => { 'group-object-container': shouldDisplayIntendedBlock, 'mx-2': typeofCurrentNode !== 'Object' && typeofCurrentNode !== 'Array', })} + id={`inspector-node-${String(currentNode).toLowerCase()}`} data-cy={`inspector-node-${String(currentNode).toLowerCase()}`} > {$NODEIcon &&
{$NODEIcon}
} From 1ad1d54c82b86358f5185aced3723f055fe07cbe Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Fri, 28 Feb 2025 16:26:07 +0530 Subject: [PATCH 03/53] Refactored the code and added conditions for tabs, modal and kanban components as parent component. --- .../useCallbackActions.js | 27 ++---------- .../_stores/slices/leftSideBarSlice.js | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js b/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js index 7067cd540d..6fea25c151 100644 --- a/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js +++ b/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js @@ -30,30 +30,11 @@ 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; - } - } - - autoScrollTo(data.id); + const computedComponentId = useStore.getState().getComponentIdToAutoScroll(data.id); + setSelectedComponents([computedComponentId]); + const target = document.getElementById(computedComponentId); + target.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }; const callbackActions = [ diff --git a/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js b/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js index 98decac629..77e8b5f284 100644 --- a/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js @@ -37,4 +37,47 @@ export const createLeftSideBarSlice = (set, get) => ({ toggleLeftSidebar(true); } }, + getComponentIdToAutoScroll: (componentId) => { + const { getCurrentPageComponents, getAllExposedValues } = get(); + const currentPageComponents = getCurrentPageComponents(); + const component = currentPageComponents?.[componentId]; + let parentId = component?.component?.parent; + + if (!parentId) { + return componentId; + } + + // 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 + + parentId = parentId.replace(regForTabs, ''); // Extract tab id from parent id + const { currentTab } = getAllExposedValues().components[parentId]; + const activeTabIndex = Number(currentTab); + + if (tabIndex !== activeTabIndex) { + return parentId; + } else return componentId; + } + + const parentExposedValues = getAllExposedValues().components[parentId]; + const parentComponent = currentPageComponents?.[parentId]; + + // If the component exists inside a modal component + if (parentComponent?.component?.component === 'Modal') { + if (parentExposedValues?.show) { + return componentId; + } else return parentId; + } + + // If the component exists inside the kanban component's modal + if (parentId.endsWith('-modal')) { + return parentId.replace(/-modal$/, ''); // Extract kanban id from parent id + } + + // If the component exists inside any other component + return componentId; + }, }); From a6e66889c27eb53de62935c6f6bcd76aca2d6182 Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Mon, 3 Mar 2025 14:07:47 +0530 Subject: [PATCH 04/53] Added state variable to keep track of open modals on canvas. --- .../src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx | 2 ++ frontend/src/AppBuilder/Widgets/Modal.jsx | 2 ++ .../AppBuilder/_stores/slices/componentsSlice.js | 14 ++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx b/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx index 34efc57221..2621708532 100644 --- a/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx +++ b/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx @@ -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(() => { diff --git a/frontend/src/AppBuilder/Widgets/Modal.jsx b/frontend/src/AppBuilder/Widgets/Modal.jsx index 5543ce4ee0..e0f099205f 100644 --- a/frontend/src/AppBuilder/Widgets/Modal.jsx +++ b/frontend/src/AppBuilder/Widgets/Modal.jsx @@ -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 ****/ diff --git a/frontend/src/AppBuilder/_stores/slices/componentsSlice.js b/frontend/src/AppBuilder/_stores/slices/componentsSlice.js index 1f6ce18405..8690c428f9 100644 --- a/frontend/src/AppBuilder/_stores/slices/componentsSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/componentsSlice.js @@ -40,6 +40,7 @@ const initialState = { currentPageHandle: null, showWidgetDeleteConfirmation: false, focusedParentId: null, + modalsOpenOnCanvas: [], }; export const createComponentsSlice = (set, get) => ({ @@ -1860,4 +1861,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; + }); + }, }); From 6dd933fa63c77df1047cbccc1eec1459fdd65cb1 Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Mon, 3 Mar 2025 14:18:22 +0530 Subject: [PATCH 05/53] Implemented logic for handling nested components. --- .../_stores/slices/leftSideBarSlice.js | 108 ++++++++++++------ 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js b/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js index 77e8b5f284..3cc424f790 100644 --- a/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js @@ -38,46 +38,84 @@ export const createLeftSideBarSlice = (set, get) => ({ } }, getComponentIdToAutoScroll: (componentId) => { - const { getCurrentPageComponents, getAllExposedValues } = get(); + const { getCurrentPageComponents, getAllExposedValues, modalsOpenOnCanvas } = get(); const currentPageComponents = getCurrentPageComponents(); - const component = currentPageComponents?.[componentId]; - let parentId = component?.component?.parent; - if (!parentId) { - return componentId; + let candidate = componentId; + let current = componentId; + const visited = new Set(); + let closedUnusedModals = false; // Flag to check if we have closed all unused modals on the canvas + + // eslint-disable-next-line no-constant-condition + while (true) { + if (visited.has(current)) break; + visited.add(current); + + const component = currentPageComponents?.[current]; + if (!component) break; + + const parentId = component?.component?.parent; + if (!parentId) break; + + let isParentInactive = false; + let newCandidate = candidate; + + // 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); + + if (tabIndex !== activeTabIndex) { + isParentInactive = true; + newCandidate = tabId; + } + } + + const parentExposedValues = getAllExposedValues().components[parentId]; + + // If the component exists inside a modal component + if (currentPageComponents?.[parentId]?.component?.component === 'Modal') { + // Close all modals that are open on the canvas until we get to the parent modal + if (modalsOpenOnCanvas.length > 0 && !closedUnusedModals) { + if (!modalsOpenOnCanvas.includes(parentId)) { + modalsOpenOnCanvas.map((modalId) => getAllExposedValues().components[modalId]?.close()); + } else { + const idx = modalsOpenOnCanvas.indexOf(parentId); + modalsOpenOnCanvas.slice(idx + 1).map((modalId) => getAllExposedValues().components[modalId]?.close()); + } + closedUnusedModals = true; + } + + if (!parentExposedValues?.show) { + isParentInactive = true; + newCandidate = parentId; + } + } + + // If the component exists inside the kanban component's modal + if (parentId.endsWith('-modal')) { + isParentInactive = true; + newCandidate = parentId.replace(/-modal$/, ''); // Extract kanban id from parent id + } + + if (isParentInactive) { + candidate = newCandidate; + current = newCandidate; + } else { + current = 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 - - parentId = parentId.replace(regForTabs, ''); // Extract tab id from parent id - const { currentTab } = getAllExposedValues().components[parentId]; - const activeTabIndex = Number(currentTab); - - if (tabIndex !== activeTabIndex) { - return parentId; - } else return componentId; + // Close all modals that are open on the canvas if the component is not inside any of the modals + if (modalsOpenOnCanvas.length > 0 && !closedUnusedModals) { + modalsOpenOnCanvas.map((modalId) => getAllExposedValues().components[modalId]?.close()); } - const parentExposedValues = getAllExposedValues().components[parentId]; - const parentComponent = currentPageComponents?.[parentId]; - - // If the component exists inside a modal component - if (parentComponent?.component?.component === 'Modal') { - if (parentExposedValues?.show) { - return componentId; - } else return parentId; - } - - // If the component exists inside the kanban component's modal - if (parentId.endsWith('-modal')) { - return parentId.replace(/-modal$/, ''); // Extract kanban id from parent id - } - - // If the component exists inside any other component - return componentId; + return candidate; }, }); From 46ab01fead51186eba26fb88cc5243d296090e14 Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Tue, 4 Mar 2025 03:09:50 +0530 Subject: [PATCH 06/53] Removed logic for closing modals and refactored the code for better readability. --- .../useCallbackActions.js | 4 +- .../_stores/slices/leftSideBarSlice.js | 67 ++++++++----------- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js b/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js index 6fea25c151..bf661ea20d 100644 --- a/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js +++ b/frontend/src/AppBuilder/LeftSidebar/LeftSidebarInspector/useCallbackActions.js @@ -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]); @@ -31,7 +32,8 @@ const useCallbackActions = () => { }; const handleAutoScrollToComponent = (data) => { - const computedComponentId = useStore.getState().getComponentIdToAutoScroll(data.id); + const computedComponentId = getComponentIdToAutoScroll(data.id); + if (!computedComponentId) return; setSelectedComponents([computedComponentId]); const target = document.getElementById(computedComponentId); target.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); diff --git a/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js b/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js index 3cc424f790..da520544b2 100644 --- a/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/leftSideBarSlice.js @@ -41,24 +41,22 @@ export const createLeftSideBarSlice = (set, get) => ({ const { getCurrentPageComponents, getAllExposedValues, modalsOpenOnCanvas } = get(); const currentPageComponents = getCurrentPageComponents(); - let candidate = componentId; + let targetComponentId = componentId; let current = componentId; const visited = new Set(); - let closedUnusedModals = false; // Flag to check if we have closed all unused modals on the canvas + 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 component = currentPageComponents?.[current]; - if (!component) break; - - const parentId = component?.component?.parent; + const parentId = currentPageComponents?.[current]?.component?.parent; if (!parentId) break; - let isParentInactive = false; - let newCandidate = candidate; + 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 @@ -67,55 +65,46 @@ export const createLeftSideBarSlice = (set, get) => ({ 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 { currentTab } = getAllExposedValues().components?.[tabId] || {}; const activeTabIndex = Number(currentTab); + nextPossibleCandidate = tabId; if (tabIndex !== activeTabIndex) { - isParentInactive = true; - newCandidate = tabId; + isComponentVisibleInParent = false; } } - const parentExposedValues = getAllExposedValues().components[parentId]; - // If the component exists inside a modal component if (currentPageComponents?.[parentId]?.component?.component === 'Modal') { - // Close all modals that are open on the canvas until we get to the parent modal - if (modalsOpenOnCanvas.length > 0 && !closedUnusedModals) { - if (!modalsOpenOnCanvas.includes(parentId)) { - modalsOpenOnCanvas.map((modalId) => getAllExposedValues().components[modalId]?.close()); - } else { - const idx = modalsOpenOnCanvas.indexOf(parentId); - modalsOpenOnCanvas.slice(idx + 1).map((modalId) => getAllExposedValues().components[modalId]?.close()); - } - closedUnusedModals = true; - } - - if (!parentExposedValues?.show) { - isParentInactive = true; - newCandidate = parentId; + nextPossibleCandidate = parentId; + if (!modalsOpenOnCanvas.includes(parentId)) { + isComponentVisibleInParent = false; } } // If the component exists inside the kanban component's modal if (parentId.endsWith('-modal')) { - isParentInactive = true; - newCandidate = parentId.replace(/-modal$/, ''); // Extract kanban id from parent id + nextPossibleCandidate = parentId.replace(/-modal$/, ''); // Extract kanban id from parent id + if (!modalsOpenOnCanvas.includes(parentId)) { + isComponentVisibleInParent = false; + } } - if (isParentInactive) { - candidate = newCandidate; - current = newCandidate; - } else { - current = parentId; + // If the open modal contains the component + if (modalsOpenOnCanvas[modalsOpenOnCanvas.length - 1] === parentId) { + isInsideOpenModal = true; } + + if (!isComponentVisibleInParent) { + targetComponentId = nextPossibleCandidate; + } + current = nextPossibleCandidate; } - // Close all modals that are open on the canvas if the component is not inside any of the modals - if (modalsOpenOnCanvas.length > 0 && !closedUnusedModals) { - modalsOpenOnCanvas.map((modalId) => getAllExposedValues().components[modalId]?.close()); + if (modalsOpenOnCanvas.length > 0 && !isInsideOpenModal) { + return undefined; } - - return candidate; + return targetComponentId; }, }); From c2c0018eb73e31e1bf7216c171f1cc2febebdac3 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Tue, 4 Feb 2025 16:12:47 +0530 Subject: [PATCH 07/53] Fix page handle being wrong when fetching from exposed values in Viewer on initial reload --- frontend/src/AppBuilder/_hooks/useAppData.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/AppBuilder/_hooks/useAppData.js b/frontend/src/AppBuilder/_hooks/useAppData.js index a8fac45c48..1b664cfa21 100644 --- a/frontend/src/AppBuilder/_hooks/useAppData.js +++ b/frontend/src/AppBuilder/_hooks/useAppData.js @@ -329,6 +329,11 @@ const useAppData = (appId, moduleId, darkMode, mode = 'edit', { environmentId, v setCurrentPageHandle(startingPage.handle); updateFeatureAccess(); setCurrentPageId(startingPage.id, moduleId); + setResolvedPageConstants({ + id: startingPage?.id, + handle: startingPage?.handle, + name: startingPage?.name, + }); setComponentNameIdMapping(moduleId); updateEventsField('events', appData.events); setCurrentVersionId(appData.editing_version?.id || appData.current_version_id); From 20f03d6e1142a2fa3c7c021ad457ee7cece13c25 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Wed, 5 Feb 2025 19:21:15 +0530 Subject: [PATCH 08/53] Fix alignment issues arising due to label width setting for input components --- .../WidgetManager/widgets/listview.js | 8 ++- .../Editor/WidgetManager/configs/listview.js | 8 ++- frontend/src/_styles/table-component.scss | 55 ++++++++++++++++++- .../apps/services/widget-config/listview.js | 2 +- 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/listview.js b/frontend/src/AppBuilder/WidgetManager/widgets/listview.js index a813bb5a0b..fec2e812b4 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/listview.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/listview.js @@ -48,8 +48,12 @@ export const listviewConfig = { data: { type: 'code', displayName: 'List data', - validation: { - schema: { type: 'array', element: { type: 'object' } }, + schema: { + type: 'union', + schemas: [ + { type: 'array', element: { type: 'object' } }, + { type: 'array', element: { type: 'string' } }, + ], defaultValue: "[{text: 'Sample text 1'}]", }, }, diff --git a/frontend/src/Editor/WidgetManager/configs/listview.js b/frontend/src/Editor/WidgetManager/configs/listview.js index a813bb5a0b..25da8f73c6 100644 --- a/frontend/src/Editor/WidgetManager/configs/listview.js +++ b/frontend/src/Editor/WidgetManager/configs/listview.js @@ -49,7 +49,13 @@ export const listviewConfig = { type: 'code', displayName: 'List data', validation: { - schema: { type: 'array', element: { type: 'object' } }, + schema: { + type: 'union', + schemas: [ + { type: 'array', element: { type: 'object' } }, + { type: 'array', element: { type: 'string' } }, + ], + }, defaultValue: "[{text: 'Sample text 1'}]", }, }, diff --git a/frontend/src/_styles/table-component.scss b/frontend/src/_styles/table-component.scss index 5e0edd5aff..100cb450cc 100644 --- a/frontend/src/_styles/table-component.scss +++ b/frontend/src/_styles/table-component.scss @@ -1467,5 +1467,56 @@ } .tj-table-tag-col-readonly { - margin-left: -2px !important; //this -ve margin offset for the margin given to each tags in overall column width -} \ No newline at end of file + margin-left: -2px !important; //this -ve margin offset for the margin given to each tags in overall column width +} + +.jet-data-table { + .table-bordered { + th, + td { + border-bottom: 1px solid var(--interactive-overlay-border-pressed) !important; + border-right: 1px solid var(--interactive-overlay-border-pressed) !important; + + &:first-child { + border-left: none !important; + } + + &:last-child { + border-right: none !important; + } + } + + thead th { + border-top: none !important; + + &:first-child { + border-left: none !important; + } + + &:last-child { + border-right: none !important; + } + } + } + + .table-striped { + tbody { + div[data-index]:nth-child(odd) { + background-color: transparent !important; + } + + div[data-index]:nth-child(even) { + background-color: var(--slate2) !important; + } + } + } +} + +// hide scrollbar on touch devices + @media (hover: none) and (pointer: coarse) { + .jet-data-table::-webkit-scrollbar { + width: 0; + height: 0; + background: transparent; + } + } diff --git a/server/src/modules/apps/services/widget-config/listview.js b/server/src/modules/apps/services/widget-config/listview.js index a813bb5a0b..d710babbf0 100644 --- a/server/src/modules/apps/services/widget-config/listview.js +++ b/server/src/modules/apps/services/widget-config/listview.js @@ -49,7 +49,7 @@ export const listviewConfig = { type: 'code', displayName: 'List data', validation: { - schema: { type: 'array', element: { type: 'object' } }, + schema: { type: 'union', schemas: [{ type: 'array', element: { type: 'object' } },{ type: 'array', element: { type: 'string' } }] }, defaultValue: "[{text: 'Sample text 1'}]", }, }, From cbfe197a28b1f4d545325ad8d91b1fcd5fe962d7 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade Date: Thu, 6 Feb 2025 11:03:51 +0530 Subject: [PATCH 09/53] fi --- frontend/src/AppBuilder/Widgets/Container.jsx | 5 +---- frontend/src/_styles/components.scss | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/AppBuilder/Widgets/Container.jsx b/frontend/src/AppBuilder/Widgets/Container.jsx index 3ccedd869b..16623280a5 100644 --- a/frontend/src/AppBuilder/Widgets/Container.jsx +++ b/frontend/src/AppBuilder/Widgets/Container.jsx @@ -45,7 +45,6 @@ export const Container = ({ border: `1px solid ${borderColor}`, height, display: isVisible ? 'flex' : 'none', - overflow: 'hidden auto', position: 'relative', boxShadow, }; @@ -66,9 +65,7 @@ export const Container = ({ return (