From c70892ba802b22c8136fc2e5c3996350477e5a13 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Wed, 26 Feb 2025 23:16:29 +0530 Subject: [PATCH 001/108] Fixed bug causing component definition to be copied on copying text --- frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js index 04ae6aa896..027734a6a1 100644 --- a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js +++ b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js @@ -240,6 +240,12 @@ const getSelectedText = () => { // TODO: Move this function to componentSlice export const copyComponents = ({ isCut = false, isCloning = false }) => { + const selectedText = window.getSelection()?.toString().trim(); + if (selectedText) { + navigator.clipboard.writeText(selectedText); + return; + } + const selectedComponents = useStore.getState().getSelectedComponentsDefinition(); if (selectedComponents.length < 1) return getSelectedText(); const allComponents = useStore.getState().getCurrentPageComponents(); From 161fffcb42785b4f8aef48ee9371c5a4a21e7756 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Thu, 27 Feb 2025 02:44:31 +0530 Subject: [PATCH 002/108] Automatically resizing codehinter input based on content --- .../QueryEditors/Restapi/TabContent.jsx | 4 ++-- .../TooljetDatabase/DropDownSelect.jsx | 4 +++- .../TooljetDatabase/JoinConstraint.jsx | 3 +-- .../TooljetDatabase/JoinSelect.jsx | 5 +---- .../QueryEditors/TooljetDatabase/JoinSort.jsx | 5 +---- .../TooljetDatabase/JoinTable.jsx | 3 +-- .../TooljetDatabase/RenderColumnUI.jsx | 5 +---- .../TooljetDatabase/RenderFilterSectionUI.jsx | 5 +---- .../TooljetDatabase/RenderSortUI.jsx | 5 +---- frontend/src/_styles/queryManager.scss | 21 +++++++++++++++++-- frontend/src/_styles/theme.scss | 1 + 11 files changed, 32 insertions(+), 29 deletions(-) diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/TabContent.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/TabContent.jsx index cf47ded427..ee55937b1c 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/TabContent.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/Restapi/TabContent.jsx @@ -30,7 +30,7 @@ export default ({ return ( <>
-
+
) : ( -
+
{index > 0 && ( diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSelect.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSelect.jsx index 4734addb26..863c826b8a 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSelect.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSelect.jsx @@ -340,10 +340,7 @@ const JsonBfieldsForSelect = ({ selectedJsonbColumns, handleJSonChange, table }) handleRemove(colDetails.id, colDetails.name, colDetails.table)} > diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSort.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSort.jsx index 2d5a2de518..9e129e9eb4 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSort.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinSort.jsx @@ -164,10 +164,7 @@ export default function JoinSort({ darkMode }) { setJoinOrderByOptions(joinOrderByOptions.filter((opt, idx) => idx !== i))} > diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinTable.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinTable.jsx index eba36f37a3..cf14448967 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinTable.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/JoinTable.jsx @@ -535,12 +535,11 @@ const RenderFilterSection = ({ darkMode }) => { removeFilterConditionEntry(index)} > diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderColumnUI.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderColumnUI.jsx index 1766691d66..89323c1c3c 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderColumnUI.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderColumnUI.jsx @@ -54,10 +54,7 @@ const RenderColumnUI = ({ removeColumnOptionsPair(id)} > diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderFilterSectionUI.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderFilterSectionUI.jsx index 983019697a..cd7f94abf3 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderFilterSectionUI.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderFilterSectionUI.jsx @@ -117,10 +117,7 @@ const RenderFilterSectionUI = ({ removeFilterConditionPair(id)} > diff --git a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderSortUI.jsx b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderSortUI.jsx index b5021974ba..a349b9e5ed 100644 --- a/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderSortUI.jsx +++ b/frontend/src/AppBuilder/QueryManager/QueryEditors/TooljetDatabase/RenderSortUI.jsx @@ -86,10 +86,7 @@ const RenderSortUI = ({ removeSortConditionPair(id)} > diff --git a/frontend/src/_styles/queryManager.scss b/frontend/src/_styles/queryManager.scss index 8a9eaf972a..ece491e06a 100644 --- a/frontend/src/_styles/queryManager.scss +++ b/frontend/src/_styles/queryManager.scss @@ -1851,8 +1851,9 @@ $border-radius: 4px; .tjdb-codhinter-wrapper{ .codehinter-input{ .cm-editor{ - height: 30px !important; + // height: 30px !important; min-height: 30px !important; + max-height:100px !important; border-radius: 0 !important; border-right: 0 ; } @@ -1860,8 +1861,9 @@ $border-radius: 4px; } .tjdb-limit-offset-codehinter{ .cm-editor{ - height: 30px !important; + // height: 30px !important; min-height: 30px !important; + max-height:100px !important; } } @@ -1899,4 +1901,19 @@ $border-radius: 4px; line-height: 18px; } } +} + + +.qm-delete-btn { + min-height: 30px; + height: 100% !important; + align-items: flex-start !important; + padding-top: 6px; +} + +.restapi-key-value { + .code-hinter-wrapper, .code-editor-basic-wrapper, .codehinter-container, .cm-codehinter, .code-editor-query-panel{ + height:100%; + max-height: 100px; + } } \ No newline at end of file diff --git a/frontend/src/_styles/theme.scss b/frontend/src/_styles/theme.scss index c999eaa525..5a223dd733 100644 --- a/frontend/src/_styles/theme.scss +++ b/frontend/src/_styles/theme.scss @@ -15810,6 +15810,7 @@ tbody { } .rest-api-options-codehinter { + height: 100%; .cm-content>.cm-line { // max-width: 357px !important; } From 550feae6b59c76d036286527c3ee1a1d35511164 Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Thu, 27 Feb 2025 23:59:12 +0530 Subject: [PATCH 003/108] 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 004/108] 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 005/108] 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 6952cd2292e79d36b127f247ec92949f6f70e598 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Sun, 2 Mar 2025 00:57:01 +0530 Subject: [PATCH 006/108] Fixed query panel resizing causing black bars issue --- .../src/AppBuilder/LeftSidebar/LeftSidebar.jsx | 14 ++++++++++---- frontend/src/AppBuilder/QueryPanel/QueryPanel.jsx | 1 + frontend/src/_styles/left-sidebar.scss | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/frontend/src/AppBuilder/LeftSidebar/LeftSidebar.jsx b/frontend/src/AppBuilder/LeftSidebar/LeftSidebar.jsx index 4146c4a28e..aaf12714b9 100644 --- a/frontend/src/AppBuilder/LeftSidebar/LeftSidebar.jsx +++ b/frontend/src/AppBuilder/LeftSidebar/LeftSidebar.jsx @@ -34,6 +34,7 @@ export const BaseLeftSidebar = ({ resetUnreadErrorCount, toggleLeftSidebar, isSidebarOpen, + isDraggingQueryPane, ] = useStore( (state) => [ state.isLeftSideBarPinned, @@ -46,6 +47,7 @@ export const BaseLeftSidebar = ({ state.debugger.resetUnreadErrorCount, state.toggleLeftSidebar, state.isSidebarOpen, + state.queryPanel.isDraggingQueryPane, ], shallow ); @@ -68,11 +70,15 @@ export const BaseLeftSidebar = ({ }; useEffect(() => { - setPopoverContentHeight( - ((window.innerHeight - (queryPanelHeight == 0 ? 40 : queryPanelHeight) - 45) / window.innerHeight) * 100 - ); + if (!isDraggingQueryPane) { + setPopoverContentHeight( + ((window.innerHeight - (queryPanelHeight == 0 ? 40 : queryPanelHeight) - 45) / window.innerHeight) * 100 + ); + } else { + setPopoverContentHeight(100); + } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [queryPanelHeight]); + }, [queryPanelHeight, isDraggingQueryPane]); const renderPopoverContent = () => { if (selectedSidebarItem === null || !isSidebarOpen) return null; diff --git a/frontend/src/AppBuilder/QueryPanel/QueryPanel.jsx b/frontend/src/AppBuilder/QueryPanel/QueryPanel.jsx index 827efe6d33..ea8623b0c1 100644 --- a/frontend/src/AppBuilder/QueryPanel/QueryPanel.jsx +++ b/frontend/src/AppBuilder/QueryPanel/QueryPanel.jsx @@ -185,6 +185,7 @@ export const QueryPanel = ({ darkMode }) => { id="query-manager" style={{ height: `calc(100% - ${isExpanded ? height : 100}%)`, + maxHeight: '93.5%', cursor: isDraggingQueryPane || isTopOfQueryPanel ? 'row-resize' : 'default', ...(!isExpanded && { border: 'none', diff --git a/frontend/src/_styles/left-sidebar.scss b/frontend/src/_styles/left-sidebar.scss index 3f68e1486b..82b6762b54 100644 --- a/frontend/src/_styles/left-sidebar.scss +++ b/frontend/src/_styles/left-sidebar.scss @@ -701,6 +701,7 @@ .sidebar-h-100-popover { position: relative; height: 100vh; + overflow-y:scroll !important; margin-top: 0px; border-radius: 0px !important; From b4ff440e8705d56207cfa7e8fd8255af6dc5caaf Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Sun, 2 Mar 2025 13:09:56 +0530 Subject: [PATCH 007/108] Fixed popover values not saving when clicking on draggable items on inspector --- .../RightSideBar/Inspector/Components/Select.jsx | 5 +++++ .../RightSideBar/Inspector/Components/Table/Table.jsx | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx index a57c879121..d0b058b7b0 100644 --- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx +++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx @@ -388,6 +388,11 @@ export function Select({ componentMeta, darkMode, ...restProps }) { placement="left" rootClose overlay={_renderOverlay(item, index)} + onToggle={(isOpen) => { + if (!isOpen) { + document.activeElement?.blur(); // Manually trigger blur when popover closes + } + }} >
this.setState({ showPopOver: showing })} + onToggle={(showing) => { + if (!showing) { + document.activeElement?.blur(); // Manually trigger blur when popover closes + } + this.setState({ showPopOver: showing }); + }} >
@@ -647,6 +652,7 @@ class TableComponent extends React.Component { if (show) { this.handleToggleColumnPopover(index); } else { + document.activeElement?.blur(); // Manually trigger blur when popover closes this.handleToggleColumnPopover(null); } }} From 3c68cd6f5a6c3b2fe390e5570b5afc7795ea99fb Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Mon, 3 Mar 2025 02:39:32 +0530 Subject: [PATCH 008/108] Code hinter issue fix --- .../src/AppBuilder/CodeEditor/PreviewBox.jsx | 16 ++- .../CodeEditor/SingleLineCodeEditor.jsx | 120 +++++++++++------- .../src/AppBuilder/CodeEditor/styles.scss | 5 + frontend/src/_styles/theme.scss | 7 +- 4 files changed, 99 insertions(+), 49 deletions(-) diff --git a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx index 2429973c25..ce12c1b250 100644 --- a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx @@ -294,13 +294,9 @@ const PreviewContainer = ({ ...restProps }) => { const { validationSchema, isWorkspaceVariable, errorStateActive, previewPlacement, validationFn } = restProps; - const [errorMessage, setErrorMessage] = useState(''); - const typeofError = getCurrentNodeType(errorMessage); - const errorMsg = typeofError === 'Array' ? errorMessage[0] : errorMessage; - const darkMode = localStorage.getItem('darkMode') === 'true'; const popover = ( { + // Force position update on first render + // This is done to avoid scroll issue + if (state.elements.popper) { + state.elements.popper.style.position = 'fixed'; + } + }, }} > {(props) => React.cloneElement(popover, props)} diff --git a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx index 1243f26f43..98325df3a8 100644 --- a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx @@ -1,5 +1,5 @@ /* eslint-disable import/no-unresolved */ -import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { PreviewBox } from './PreviewBox'; import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip'; import { useTranslation } from 'react-i18next'; @@ -31,6 +31,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r const [currentValue, setCurrentValue] = useState(''); const [errorStateActive, setErrorStateActive] = useState(false); const [cursorInsidePreview, setCursorInsidePreview] = useState(false); + const [showSuggestions, setShowSuggestions] = useState(true); const validationFn = restProps?.validationFn; const componentDefinition = useStore((state) => state.getComponentDefinition(componentId), shallow); const parentId = componentDefinition?.component?.parent; @@ -38,6 +39,30 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r const customVariables = customResolvables?.[parentId]?.[0] || {}; + useEffect(() => { + const observer = new IntersectionObserver( + ([entry]) => { + if (entry.intersectionRatio < 1) { + setShowPreview(false); + setShowSuggestions(false); + } else { + setShowSuggestions(true); + } + }, + { root: null, threshold: [1] } // Fires when any part of the element is out of view + ); + + if (wrapperRef.current) { + observer.observe(wrapperRef.current); + } + + return () => { + if (wrapperRef.current) { + observer.unobserve(wrapperRef.current); + } + }; + }, []); + const isPreviewFocused = useRef(false); const wrapperRef = useRef(null); @@ -136,6 +161,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r componentName={componentName} setShowPreview={setShowPreview} showPreview={showPreview} + showSuggestions={showSuggestions} {...restProps} />
@@ -168,6 +194,7 @@ const EditorInput = ({ previewRef, setShowPreview, onInputChange, + showSuggestions, }) => { const getSuggestions = useStore((state) => state.getSuggestions, shallow); function autoCompleteExtensionConfig(context) { @@ -223,7 +250,7 @@ const EditorInput = ({ defaultKeymap: true, positionInfo: () => { return { - class: 'cm-completionInfo-top cm-custom-completion-info', + class: 'cm-completionInfo-top cm-custom-completion-info cm-custom-singleline-completion-info', }; }, maxRenderedOptions: 10, @@ -339,15 +366,6 @@ const EditorInput = ({ data-cy={`${cyLabel}-input-field`} > {/* sticky element to position the preview box correctly on top without flowing out of container */} -
{usePortalEditor && ( - { - setFirstTimeFocus(false); - handleOnChange(val); - onInputChange && onInputChange(val); +
handleFocus()} - onBlur={() => handleOnBlur()} - className={customClassNames} - theme={theme} - indentWithTab={false} - readOnly={disabled} - /> + className="check-here" + ref={previewRef} + > + { + setFirstTimeFocus(false); + handleOnChange(val); + onInputChange && onInputChange(val); + }} + basicSetup={{ + lineNumbers: showLineNumbers, + syntaxHighlighting: true, + bracketMatching: true, + foldGutter: false, + highlightActiveLine: false, + autocompletion: showSuggestions, + completionKeymap: true, + searchKeymap: false, + }} + onMouseDown={() => handleFocus()} + onBlur={() => handleOnBlur()} + className={customClassNames} + theme={theme} + indentWithTab={false} + readOnly={disabled} + /> +
diff --git a/frontend/src/AppBuilder/CodeEditor/styles.scss b/frontend/src/AppBuilder/CodeEditor/styles.scss index c646fd30b1..73ba4ac36e 100644 --- a/frontend/src/AppBuilder/CodeEditor/styles.scss +++ b/frontend/src/AppBuilder/CodeEditor/styles.scss @@ -651,4 +651,9 @@ .cm-searchMatch.cm-searchMatch-selected { background-color: #F28F2D; +} + + +.cm-custom-singleline-completion-info { + display: none; } \ No newline at end of file diff --git a/frontend/src/_styles/theme.scss b/frontend/src/_styles/theme.scss index c999eaa525..84b1d6dc80 100644 --- a/frontend/src/_styles/theme.scss +++ b/frontend/src/_styles/theme.scss @@ -1544,7 +1544,7 @@ button { .tab-content { overflow-y: auto; // TAB HEADER HEIGHT + FOOTER HEIGHT + Extra padding = 120px - height: calc(100vh - 7.5rem); + height: calc(100vh - 10.4rem); // Hide scrollbar -ms-overflow-style: none; /* IE and Edge */ @@ -18562,4 +18562,9 @@ section.ai-message-prompt-input-wrapper { margin-left: 8px; flex-grow: 1; } +} + + +.cm-tooltip { + z-index: 9999 !important; } \ No newline at end of file From 5e826c2f6fe60575760d6fd02f91fd59a09f8f78 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Mon, 3 Mar 2025 12:33:17 +0530 Subject: [PATCH 009/108] Dropdown breaking fix --- .../RightSideBar/Inspector/Components/Select.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx index d0b058b7b0..456b54cd02 100644 --- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx +++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Select.jsx @@ -297,7 +297,7 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
{options?.map((item, index) => { return ( - + {(provided, snapshot) => (
-
+
setHoveredOptionIndex(index)} @@ -406,7 +406,7 @@ export function Select({ componentMeta, darkMode, ...restProps }) {
- {getResolvedValue(item.label)} + {getResolvedValue(item?.label)}
{index === hoveredOptionIndex && ( From a6e66889c27eb53de62935c6f6bcd76aca2d6182 Mon Sep 17 00:00:00 2001 From: devanshu052000 Date: Mon, 3 Mar 2025 14:07:47 +0530 Subject: [PATCH 010/108] 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 011/108] 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 012/108] 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 013/108] 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 014/108] 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 015/108] 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 (