From 3933a9e7a25694d829cf563a452b546fcfd2a510 Mon Sep 17 00:00:00 2001
From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Date: Sat, 8 Mar 2025 00:25:24 +0530
Subject: [PATCH 01/12] Adds header and footer slots for Form
---
.../AppBuilder/AppCanvas/appCanvasUtils.js | 9 +-
.../Inspector/Components/Form.jsx | 52 +++-
.../AppBuilder/WidgetManager/widgets/form.js | 111 +++++--
frontend/src/AppBuilder/Widgets/Form/Form.jsx | 282 +++++++++++-------
.../src/Editor/WidgetManager/configs/form.js | 110 +++++--
.../apps/services/widget-config/form.js | 110 +++++--
6 files changed, 503 insertions(+), 171 deletions(-)
diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
index 4e7b56ea70..41bc116ec3 100644
--- a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
+++ b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
@@ -206,6 +206,7 @@ export const getAllChildComponents = (allComponents, parentId) => {
allComponents[parentId]?.component?.component === 'Calendar' ||
allComponents[parentId]?.component?.component === 'Kanban' ||
allComponents[parentId]?.component?.component === 'Container' ||
+ allComponents[parentId]?.component?.component === 'Form' ||
allComponents[parentId]?.component?.component === 'ModalV2';
if (componentParentId && isParentTabORCalendar) {
@@ -327,6 +328,7 @@ const isChildOfTabsOrCalendar = (component, allComponents = [], componentParentI
parentComponent.component.component === 'Tabs' ||
parentComponent.component.component === 'Calendar' ||
parentComponent.component.component === 'Container' ||
+ parentComponent.component.component === 'Form' ||
parentComponent.component.component === 'ModalV2'
);
}
@@ -665,11 +667,14 @@ export const computeViewerBackgroundColor = (isAppDarkMode, canvasBgColor) => {
return canvasBgColor;
};
-export const getParentComponentIdByType = ({ child, parentComponent, parentId, slotName = 'header' }) => {
+export const getParentComponentIdByType = ({ child, parentComponent, parentId, slotName }) => {
const { tab } = child;
if (parentComponent === 'Tabs') return `${parentId}-${tab}`;
- else if (parentComponent === 'Container' || parentComponent === 'ModalV2') {
+ else if (
+ slotName &&
+ (parentComponent === 'Form' || parentComponent === 'Container' || parentComponent === 'ModalV2')
+ ) {
return `${parentId}-${slotName}`;
}
return parentId;
diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Form.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Form.jsx
index d4676ad4b6..b39924854e 100644
--- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Form.jsx
+++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/Form.jsx
@@ -19,16 +19,34 @@ export const Form = ({
allComponents,
pages,
}) => {
- const properties = Object.keys(componentMeta.properties);
+ const tempComponentMeta = deepClone(componentMeta);
+
+ let properties = [];
+ let additionalActions = [];
+ let dataProperties = [];
+
const events = Object.keys(componentMeta.events);
const validations = Object.keys(componentMeta.validation || {});
- const tempComponentMeta = deepClone(componentMeta);
+
+ for (const [key] of Object.entries(componentMeta?.properties)) {
+ if (componentMeta?.properties[key]?.section === 'additionalActions') {
+ additionalActions.push(key);
+ } else if (componentMeta?.properties[key]?.accordian === 'Data') {
+ dataProperties.push(key);
+ } else {
+ properties.push(key);
+ }
+ }
const { id } = component;
const newOptions = [{ name: 'None', value: 'none' }];
- Object.entries(allComponents).forEach(([componentId, component]) => {
- if (component.component.parent === id && component?.component?.component === 'Button') {
- newOptions.push({ name: component.component.name, value: componentId });
+ Object.entries(allComponents).forEach(([componentId, _component]) => {
+ const validParent =
+ _component.component.parent === id ||
+ _component.component.parent === `${id}-footer` ||
+ _component.component.parent === `${id}-header`;
+ if (validParent && _component?.component?.component === 'Button') {
+ newOptions.push({ name: _component.component.name, value: componentId });
}
});
@@ -48,7 +66,8 @@ export const Form = ({
allComponents,
validations,
darkMode,
- pages
+ pages,
+ additionalActions
);
return ;
@@ -68,7 +87,8 @@ export const baseComponentProperties = (
allComponents,
validations,
darkMode,
- pages
+ pages,
+ additionalActions
) => {
let items = [];
if (properties.length > 0) {
@@ -90,6 +110,24 @@ export const baseComponentProperties = (
});
}
+ items.push({
+ title: 'Additional actions',
+ isOpen: true,
+ children: additionalActions?.map((property) =>
+ renderElement(
+ component,
+ componentMeta,
+ paramUpdated,
+ dataQueries,
+ property,
+ 'properties',
+ currentState,
+ allComponents,
+ darkMode
+ )
+ ),
+ });
+
if (events.length > 0) {
items.push({
title: `${i18next.t('widget.common.events', 'Events')}`,
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/form.js b/frontend/src/AppBuilder/WidgetManager/widgets/form.js
index 0e9f5f4ce3..7ab4bd26a6 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/form.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/form.js
@@ -4,9 +4,40 @@ export const formConfig = {
description: 'Wrapper for multiple components',
defaultSize: {
width: 13,
- height: 330,
+ height: 480,
},
defaultChildren: [
+ {
+ componentName: 'Text',
+ slotName: 'header',
+ layout: {
+ top: 10,
+ left: 1,
+ height: 40,
+ },
+ properties: ['text'],
+ accessorKey: 'text',
+ styles: ['fontWeight', 'textSize', 'textColor'],
+ defaultValue: {
+ text: 'Form title',
+ textSize: 20,
+ textColor: '#000',
+ },
+ },
+ {
+ componentName: 'Button',
+ slotName: 'footer',
+ layout: {
+ top: 12,
+ left: 32,
+ height: 36,
+ },
+ properties: ['text'],
+ defaultValue: {
+ text: 'Button2',
+ padding: 'none',
+ },
+ },
{
componentName: 'Text',
layout: {
@@ -225,6 +256,7 @@ export const formConfig = {
loadingState: {
type: 'toggle',
displayName: 'Loading state',
+ section: 'additionalActions',
validation: {
schema: { type: 'boolean' },
defaultValue: false,
@@ -242,12 +274,64 @@ export const formConfig = {
value: true,
},
},
+ showHeader: { type: 'toggle', displayName: 'Header' },
+ showFooter: { type: 'toggle', displayName: 'Footer' },
+ visibility: {
+ type: 'toggle',
+ displayName: 'Visibility',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: true,
+ },
+ },
+ disabledState: {
+ type: 'toggle',
+ displayName: 'Disable',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ },
},
events: {
onSubmit: { displayName: 'On submit' },
onInvalid: { displayName: 'On invalid' },
},
styles: {
+ headerBackgroundColor: {
+ type: 'color',
+ displayName: 'Header background color',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#ffffffff',
+ },
+ },
+ footerBackgroundColor: {
+ type: 'color',
+ displayName: 'Footer background color',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#ffffffff',
+ },
+ },
+ headerHeight: {
+ type: 'code',
+ displayName: 'Header height',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '80px',
+ },
+ },
+ footerHeight: {
+ type: 'code',
+ displayName: 'Footer height',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '80px',
+ },
+ },
backgroundColor: {
type: 'color',
displayName: 'Background color',
@@ -274,22 +358,6 @@ export const formConfig = {
defaultValue: '#fff',
},
},
- visibility: {
- type: 'toggle',
- displayName: 'Visibility',
- validation: {
- schema: { type: 'boolean' },
- defaultValue: true,
- },
- },
- disabledState: {
- type: 'toggle',
- displayName: 'Disable',
- validation: {
- schema: { type: 'boolean' },
- defaultValue: false,
- },
- },
},
exposedVariables: {
data: {},
@@ -317,15 +385,18 @@ export const formConfig = {
value:
"{{ {title: 'User registration form', properties: {firstname: {type: 'textinput',value: 'Maria',label:'First name', validation:{maxLength:6}, styles: {backgroundColor: '#f6f5ff',textColor: 'black'},},lastname:{type: 'textinput',value: 'Doe', label:'Last name', styles: {backgroundColor: '#f6f5ff',textColor: 'black'},},age:{type:'number', label:'Age'},}, submitButton: {value: 'Submit', styles: {backgroundColor: '#3a433b',borderColor:'#595959'}}} }}",
},
- buttonToSubmit: { value: '{{"none"}}' },
+ showHeader: { value: '{{false}}' },
+ showFooter: { value: '{{false}}' },
+ visibility: { value: '{{true}}' },
+ disabledState: { value: '{{false}}' },
},
events: [],
styles: {
backgroundColor: { value: '#fff' },
borderRadius: { value: '0' },
borderColor: { value: '#fff' },
- visibility: { value: '{{true}}' },
- disabledState: { value: '{{false}}' },
+ headerHeight: { value: '60px' },
+ footerHeight: { value: '60px' },
},
},
};
diff --git a/frontend/src/AppBuilder/Widgets/Form/Form.jsx b/frontend/src/AppBuilder/Widgets/Form/Form.jsx
index 674d707f03..c9ea9b7601 100644
--- a/frontend/src/AppBuilder/Widgets/Form/Form.jsx
+++ b/frontend/src/AppBuilder/Widgets/Form/Form.jsx
@@ -13,6 +13,12 @@ import RenderSchema from './RenderSchema';
import useStore from '@/AppBuilder/_stores/store';
import { shallow } from 'zustand/shallow';
+const getCanvasHeight = (height) => {
+ const parsedHeight = height.includes('px') ? parseInt(height, 10) : height;
+
+ return Math.ceil(parsedHeight);
+};
+
export const Form = function Form(props) {
const {
id,
@@ -29,8 +35,25 @@ export const Form = function Form(props) {
dataCy,
} = props;
const childComponents = useStore((state) => state.getChildComponents(id), shallow);
- const { visibility, disabledState, borderRadius, borderColor, boxShadow } = styles;
- const { buttonToSubmit, loadingState, advanced, JSONSchema } = properties;
+ const {
+ borderRadius,
+ borderColor,
+ boxShadow,
+ headerHeight,
+ footerHeight,
+ footerBackgroundColor,
+ headerBackgroundColor,
+ } = styles;
+ const {
+ buttonToSubmit,
+ loadingState,
+ advanced,
+ JSONSchema,
+ showHeader = false,
+ showFooter = false,
+ visibility,
+ disabledState,
+ } = properties;
const backgroundColor =
['#fff', '#ffffffff'].includes(styles.backgroundColor) && darkMode ? '#232E3C' : styles.backgroundColor;
const computedStyles = {
@@ -40,16 +63,32 @@ export const Form = function Form(props) {
height,
display: visibility ? 'flex' : 'none',
position: 'relative',
- overflow: 'hidden auto',
boxShadow,
+ flexDirection: 'column',
};
- const childIdNameMap = useMemo(() => {
- return Object.keys(childComponents).reduce((acc, id) => {
- const component = childComponents[id]?.component?.component;
- return { ...acc, [id]: component?.name };
- }, {});
- }, [childComponents]);
+ const formHeader = {
+ flexShrink: 0,
+ // height: headerHeight,
+ padding: '10px 6px',
+ borderBottom: '1px solid var(--border-weak)',
+ backgroundColor:
+ ['#fff', '#ffffffff'].includes(headerBackgroundColor) && darkMode ? '#1F2837' : headerBackgroundColor,
+ };
+ const formFooter = {
+ flexShrink: 0,
+ // height: footerHeight,
+ padding: '10px 6px',
+ borderTop: '1px solid var(--border-weak)',
+ backgroundColor:
+ ['#fff', '#ffffffff'].includes(footerBackgroundColor) && darkMode ? '#1F2837' : footerBackgroundColor,
+ };
+ const formContent = {
+ overflow: 'hidden auto',
+ display: 'flex',
+ height: '100%',
+ padding: '10px 6px',
+ };
const parentRef = useRef(null);
const childDataRef = useRef({});
@@ -58,6 +97,8 @@ export const Form = function Form(props) {
const [isValid, setValidation] = useState(true);
const [uiComponents, setUIComponents] = useState([]);
const mounted = useMounted();
+ const canvasHeaderHeight = getCanvasHeight(headerHeight) / 10;
+ const canvasFooterHeight = getCanvasHeight(footerHeight) / 10;
useEffect(() => {
const exposedVariables = {
@@ -155,7 +196,7 @@ export const Form = function Form(props) {
};
setExposedVariables(exposedVariables);
setValidation(childValidation);
- }, [childrenData, advanced, JSON.stringify(childIdNameMap)]);
+ }, [childrenData, advanced]);
useEffect(() => {
document.addEventListener('submitForm', handleFormSubmission);
@@ -245,105 +286,138 @@ export const Form = function Form(props) {
if (e.target.className === 'real-canvas') onComponentClick(id, component);
}} //Hack, should find a better solution - to prevent losing z index+1 when container element is clicked
>
- {loadingState ? (
-
-
-
-
+ {showHeader && (
+
+
- ) : (
-
{showFooter && (
-
+
)}
diff --git a/frontend/src/AppBuilder/Widgets/Form/form.scss b/frontend/src/AppBuilder/Widgets/Form/form.scss
new file mode 100644
index 0000000000..88a5ad055e
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/Form/form.scss
@@ -0,0 +1,25 @@
+.wj-form-header {
+ position: relative;
+ &::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: -7px;
+ right: -7px;
+ height: 1px;
+ background-color: var(--border-weak);
+ }
+}
+
+.wj-form-footer {
+ position: relative;
+ &::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -7px;
+ right: -7px;
+ height: 1px;
+ background-color: var(--border-weak);
+ }
+}
diff --git a/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx b/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx
index 34efc57221..649e79f451 100644
--- a/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx
+++ b/frontend/src/AppBuilder/Widgets/Kanban/KanbanBoard.jsx
@@ -410,6 +410,7 @@ export function KanbanBoard({ widgetHeight, kanbanProps, parentRef, id }) {
width: `${(Number(cardWidth) || 300) + 48}px`,
}}
kanbanProps={kanbanProps}
+ componentType="Kanban"
>
{items[columnId] && (
diff --git a/frontend/src/AppBuilder/Widgets/Listview.jsx b/frontend/src/AppBuilder/Widgets/Listview.jsx
index 5ec5abbb17..285f9e5bf9 100644
--- a/frontend/src/AppBuilder/Widgets/Listview.jsx
+++ b/frontend/src/AppBuilder/Widgets/Listview.jsx
@@ -12,11 +12,8 @@ import { shallow } from 'zustand/shallow';
export const Listview = function Listview({
id,
- component,
width,
height,
- containerProps,
- removeComponent,
properties,
styles,
fireEvent,
@@ -270,38 +267,8 @@ export const Listview = function Listview({
columns={positiveColumns}
listViewMode={mode}
darkMode={darkMode}
+ componentType="Listview"
/>
- {/* {
- const changedData = { [component.name]: { [optionName]: value } };
- const existingDataAtIndex = prevData[index] ?? {};
- const newDataAtIndex = {
- ...prevData[index],
- [component.name]: {
- ...existingDataAtIndex[component.name],
- ...changedData[component.name],
- id: componentId,
- },
- };
- const newChildrenData = { ...prevData, [index]: newDataAtIndex };
- return { ...prevData, ...newChildrenData };
- });
- }}
- /> */}
))}
diff --git a/frontend/src/AppBuilder/Widgets/Tabs.jsx b/frontend/src/AppBuilder/Widgets/Tabs.jsx
index 3a93fa698b..7f4fb527e4 100644
--- a/frontend/src/AppBuilder/Widgets/Tabs.jsx
+++ b/frontend/src/AppBuilder/Widgets/Tabs.jsx
@@ -126,6 +126,7 @@ export const Tabs = function Tabs({
allowContainerSelect={true}
styles={{ backgroundColor: bgColor }}
darkMode={darkMode}
+ componentType="Tabs"
/>
);
diff --git a/frontend/src/AppBuilder/_helpers/editorHelpers.js b/frontend/src/AppBuilder/_helpers/editorHelpers.js
index 38e9abd955..5e817c7f7e 100644
--- a/frontend/src/AppBuilder/_helpers/editorHelpers.js
+++ b/frontend/src/AppBuilder/_helpers/editorHelpers.js
@@ -59,7 +59,7 @@ import { BoundedBox } from '@/Editor/Components/BoundedBox/BoundedBox';
import { isPDFSupported } from '@/_helpers/appUtils';
import { resolveWidgetFieldValue } from '@/_helpers/utils';
import { useEditorStore } from '@/_stores/editorStore';
-import { Container } from '@/AppBuilder/Widgets/Container';
+import { Container } from '@/AppBuilder/Widgets/Container/Container';
import { Listview } from '@/AppBuilder/Widgets/Listview';
import { Tabs } from '@/AppBuilder/Widgets/Tabs';
import { Kanban } from '@/AppBuilder/Widgets/Kanban/Kanban';
From c031d5971865c25e03919037fcaecdc763cf66b4 Mon Sep 17 00:00:00 2001
From: Nakul Nagargade
Date: Wed, 19 Feb 2025 21:00:12 +0530
Subject: [PATCH 07/12] replace settings icon with ne solid icon
---
.../AppCanvas/ConfigHandle/ConfigHandle.jsx | 62 ++++++++++---------
.../AppBuilder/AppCanvas/WidgetWrapper.jsx | 2 +
2 files changed, 34 insertions(+), 30 deletions(-)
diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx
index e3e38999f3..4deb50ea2e 100644
--- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx
@@ -3,6 +3,7 @@ import { shallow } from 'zustand/shallow';
import './configHandle.scss';
import useStore from '@/AppBuilder/_stores/store';
import { findHighestLevelofSelection } from '../Grid/gridUtils';
+import SolidIcon from '@/_ui/Icon/solidIcons/index';
const CONFIG_HANDLE_HEIGHT = 20;
const BUFFER_HEIGHT = 1;
@@ -73,6 +74,7 @@ export const ConfigHandle = ({
background:
visibility === false ? '#c6cad0' : componentType === 'Modal' && isModalOpen ? '#c6cad0' : '#4D72FA',
border: position === 'bottom' ? '1px solid white' : 'none',
+ color: visibility === false && 'var(--text-placeholder)',
}}
className="badge handle-content"
>
@@ -86,42 +88,42 @@ export const ConfigHandle = ({
data-cy={`${componentName?.toLowerCase()}-config-handle`}
className="text-truncate"
>
-
+ {/* Settings Icon */}
+
+
+
{componentName}
+ {/* Divider */}
+
+ {/* Delete Button */}
{!isMultipleComponentsSelected && !shouldFreeze && (
-
-

{
+ deleteComponents([id]);
+ }}
+ >
+
setComponentToInspect(componentName)}
- data-cy={`${componentName.toLowerCase()}-inspect-button`}
- className="config-handle-inspect"
+ fill={visibility === false ? 'var(--text-placeholder)' : '#fff'}
/>
-
{
- deleteComponents([id]);
- }}
- data-cy={`${componentName.toLowerCase()}-delete-button`}
- className="delete-icon"
- />
-
+
)}
diff --git a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx
index ff22963444..895697091f 100644
--- a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx
@@ -52,7 +52,9 @@ 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',
};
+
if (!componentType) return null;
return (
<>
From 53e7de02477c756b48de24f141dc55aec915ba75 Mon Sep 17 00:00:00 2001
From: Nakul Nagargade
Date: Mon, 10 Mar 2025 13:25:20 +0530
Subject: [PATCH 08/12] Fix config handle
---
.../AppCanvas/ConfigHandle/ConfigHandle.jsx | 34 +++++++++++++------
.../AppCanvas/ConfigHandle/configHandle.scss | 17 +---------
2 files changed, 25 insertions(+), 26 deletions(-)
diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx
index 4deb50ea2e..4c558f3cc2 100644
--- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/ConfigHandle.jsx
@@ -111,19 +111,33 @@ export const ConfigHandle = ({
{/* Delete Button */}
{!isMultipleComponentsSelected && !shouldFreeze && (
- {
- deleteComponents([id]);
- }}
- >
-
+
setComponentToInspect(componentName)}
+ data-cy={`${componentName.toLowerCase()}-inspect-button`}
+ className="config-handle-inspect"
/>
-
+ {
+ deleteComponents([id]);
+ }}
+ data-cy={`${componentName.toLowerCase()}-delete-button`}
+ >
+
+
+
)}
diff --git a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss
index e7322959e5..5cb1b94268 100644
--- a/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss
+++ b/frontend/src/AppBuilder/AppCanvas/ConfigHandle/configHandle.scss
@@ -31,22 +31,7 @@
.badge {
font-size: 9px;
border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
-
- .delete-part {
- margin-left: 10px;
- float: right;
- }
-
- .delete-part::before {
- height: 12px;
- display: inline-block;
- width: 2px;
- background-color: rgba(255, 255, 255, 0.8);
- opacity: 0.5;
- content: "";
- vertical-align: middle;
- }
+ border-bottom-right-radius: 0
}
}
From 753f3384e9623a9d73bcef10f1b2d405b86c5eb5 Mon Sep 17 00:00:00 2001
From: Nakul Nagargade
Date: Mon, 10 Mar 2025 13:27:19 +0530
Subject: [PATCH 09/12] fix conflict
---
frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
index 6403d63201..559c70fe86 100644
--- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
@@ -884,7 +884,7 @@ export default function Grid({ gridWidth, currentLayout }) {
onDrag={(e) => {
// Since onDrag is called multiple times when dragging, hence we are using isDraggingRef to prevent setting state again and again
if (!isDraggingRef.current) {
- useGridStore.getState().actions.setDraggingComponentId(e.target.id);
+ useStore.getState().setDraggingComponentId(e.target.id);
showGridLines();
isDraggingRef.current = true;
}
From 3af5166422e53be73839c7ce70f7bb3733e7ef4b Mon Sep 17 00:00:00 2001
From: Nakul Nagargade
Date: Mon, 10 Mar 2025 13:42:21 +0530
Subject: [PATCH 10/12] Resolve conflict issues
---
frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
index 559c70fe86..9964b06542 100644
--- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
@@ -56,7 +56,7 @@ export default function Grid({ gridWidth, currentLayout }) {
const getHoveredComponentForGrid = useStore((state) => state.getHoveredComponentForGrid, shallow);
const getResolvedComponent = useStore((state) => state.getResolvedComponent, shallow);
const [canvasBounds, setCanvasBounds] = useState(CANVAS_BOUNDS);
- const draggingComponentId = useGridStore((state) => state.draggingComponentId, shallow);
+ const draggingComponentId = useStore((state) => state.draggingComponentId, shallow);
const resizingComponentId = useGridStore((state) => state.resizingComponentId, shallow);
const [dragParentId, setDragParentId] = useState(null);
const [elementGuidelines, setElementGuidelines] = useState([]);
@@ -641,8 +641,7 @@ export default function Grid({ gridWidth, currentLayout }) {
const currentWidget = boxList.find(({ id }) => {
return id === e.target.id;
});
- document.getElementById('real-canvas')?.classList.remove('show-grid');
- document.getElementById('canvas-' + currentWidget.component?.parent)?.classList.remove('show-grid');
+ hideGridLines();
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;
From 7b0fda5037d92b62bc736cae6fd0779b8b478981 Mon Sep 17 00:00:00 2001
From: Nakul Nagargade
Date: Thu, 27 Feb 2025 15:04:25 +0530
Subject: [PATCH 11/12] [feat] : Highlight when the component will be placed
inside the container based components
---
.../src/AppBuilder/AppCanvas/Grid/Grid.css | 69 ++++-------------
.../src/AppBuilder/AppCanvas/Grid/Grid.jsx | 19 ++++-
.../AppBuilder/AppCanvas/Grid/gridUtils.js | 76 ++++++++++++++++++-
.../AppBuilder/AppCanvas/WidgetWrapper.jsx | 1 +
.../AppBuilder/AppCanvas/appCanvasUtils.js | 16 ++++
.../src/AppBuilder/AppCanvas/selecto.scss | 19 +++--
6 files changed, 135 insertions(+), 65 deletions(-)
diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.css b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.css
index 5abcc430d4..e1c6bb3baa 100644
--- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.css
+++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.css
@@ -1,17 +1,6 @@
.target, .nested-target {
position: absolute;
- /* width: 100px;
- height: 100px; */
- /* top: 150px;
- left: 100px; */
- /* line-height: 100px; */
- /* text-align: center; */
- /* background: #ee8; */
- /* color: #333; */
- /* font-weight: bold; */
box-sizing: border-box;
- /* transition: transform 0.1s; */
- /* z-index: 3001; */
}
.target.hovered{
@@ -76,43 +65,6 @@
background: #8DA4EF !important;
}
-
-
-/* Hides all the control lines*/
-/* .moveable-line {
- color: transparent !important;
- --moveable-color: transparent !important;
-}
-
-.moveable-control {
- visibility: hidden;
-}
-
-.target {
- outline: 1px solid #4af;
-} */
-
-
-.main-editor-canvas .widget-target:not(:has(.widget-target:hover)):hover {
- outline: 1px solid #4af;
- z-index: 4 !important;
-}
-
-.main-editor-canvas .widget-target:has(.nested-target:hover):hover {
- outline: 0px solid #4af;
-}
-
-
-.main-editor-canvas .nested-target:not(:has(.nested-target:hover)):hover {
- outline: 1px solid #4af;
- z-index: 4 !important;
-}
-
-.active-target, .resizing-target {
- outline: 1px solid #4af !important;
- /* z-index: 1000000 !important; */
-}
-
.moveable-control-box:not([data-able-groupable]) .moveable-control-box:not(:hover) {
opacity: 0;
}
@@ -141,10 +93,6 @@
height: 0px !important;
}
-.resizing-target * {
- opacity: 0;
-}
-
.moveable-control {
width: 8px !important;
@@ -210,4 +158,19 @@
.moveable-guideline-group {
z-index: 9999;
-}
\ No newline at end of file
+}
+
+.dragging-component-canvas {
+ outline: 1px solid var(--border-accent-strong) !important;
+ outline-offset: 0px; /* Creates space between element and outline */
+ z-index: 999 !important;
+}
+
+.non-dragging-component {
+ outline: 1px dotted var(--border-accent-weak) !important;
+ outline-offset: 0px; /* Creates space between element and outline */
+ z-index: 999 !important;
+}
+
+
+
diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
index 9964b06542..44f148a000 100644
--- a/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/Grid/Grid.jsx
@@ -19,6 +19,9 @@ import {
adjustWidth,
hideGridLines,
showGridLines,
+ handleActivateTargets,
+ handleDeactivateTargets,
+ handleActivateNonDraggingComponents,
} from './gridUtils';
import { useAppVersionStore } from '@/_stores/appVersionStore';
import { resolveWidgetFieldValue } from '@/_helpers/utils';
@@ -580,7 +583,7 @@ export default function Grid({ gridWidth, currentLayout }) {
} else {
document.getElementById('real-canvas').classList.add('show-grid');
}
-
+ handleActivateTargets(currentWidget.component?.parent);
const currentWidth = currentWidget.width * _gridWidth;
const diffWidth = e.width - currentWidth;
const diffHeight = e.height - currentWidget.height;
@@ -632,6 +635,7 @@ export default function Grid({ gridWidth, currentLayout }) {
if (!isComponentVisible(e.target.id)) {
return false;
}
+ handleActivateNonDraggingComponents();
useGridStore.getState().actions.setResizingComponentId(e.target.id);
e.setMin([gridWidth, GRID_HEIGHT]);
}}
@@ -695,17 +699,19 @@ export default function Grid({ gridWidth, currentLayout }) {
} catch (error) {
console.error('ResizeEnd error ->', error);
}
+ handleDeactivateTargets();
setDragParentId(null);
toggleCanvasUpdater();
}}
onResizeGroupStart={({ events }) => {
showGridLines();
+ handleActivateNonDraggingComponents();
}}
onResizeGroup={({ events }) => {
const parentElm = events[0].target.closest('.real-canvas');
const parentWidth = parentElm?.clientWidth;
const parentHeight = parentElm?.clientHeight;
-
+ handleActivateTargets(parentElm?.id?.replace('canvas-', ''));
const { posRight, posLeft, posTop, posBottom } = getPositionForGroupDrag(events, parentWidth, parentHeight);
events.forEach((ev) => {
ev.target.style.width = `${ev.width}px`;
@@ -774,6 +780,7 @@ export default function Grid({ gridWidth, currentLayout }) {
} catch (error) {
console.error('Error resizing group', error);
}
+ handleDeactivateTargets();
toggleCanvasUpdater();
}}
checkInput
@@ -784,6 +791,7 @@ export default function Grid({ gridWidth, currentLayout }) {
}
newDragParentId.current = boxList.find((box) => box.id === e.target.id)?.parent;
e?.moveable?.controlBox?.removeAttribute('data-off-screen');
+
const box = boxList.find((box) => box.id === e.target.id);
// Prevent drag if shift is pressed for SUBCONTAINER_WIDGETS
if (SUBCONTAINER_WIDGETS.includes(box?.component?.component) && e.inputEvent.shiftKey) {
@@ -817,7 +825,6 @@ export default function Grid({ gridWidth, currentLayout }) {
container.contains(e.inputEvent.target)
);
}
-
if (['RangeSlider', 'BoundedBox'].includes(box?.component?.component) || isDragOnInnerElement) {
const targetElems = document.elementsFromPoint(e.clientX, e.clientY);
const isHandle = targetElems.find((ele) => ele.classList.contains('handle-content'));
@@ -825,8 +832,10 @@ export default function Grid({ gridWidth, currentLayout }) {
return false;
}
}
+ handleActivateNonDraggingComponents();
}}
onDragEnd={(e) => {
+ handleDeactivateTargets();
try {
if (isDraggingRef.current) {
useStore.getState().setDraggingComponentId(null);
@@ -961,6 +970,7 @@ export default function Grid({ gridWidth, currentLayout }) {
setDragParentId(newParentId === 'canvas' ? null : newParentId);
newDragParentId.current = newParentId === 'canvas' ? null : newParentId;
prevDragParentId.current = newParentId;
+ handleActivateTargets(newParentId);
}
}
// Postion ghost element exactly as same at dragged element
@@ -987,14 +997,17 @@ export default function Grid({ gridWidth, currentLayout }) {
ev.target.style.transform = `translate(${left}px, ${top}px)`;
});
+ handleActivateTargets(parentElm?.id?.replace('canvas-', ''));
updateNewPosition(events);
}}
onDragGroupStart={({ events }) => {
showGridLines();
setIsGroupDragging(true);
+ handleActivateNonDraggingComponents();
}}
onDragGroupEnd={(e) => {
handleDragGroupEnd(e);
+ handleDeactivateTargets();
toggleCanvasUpdater();
}}
onClickGroup={(e) => {
diff --git a/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js b/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js
index 2889fc06db..da179bc11d 100644
--- a/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js
+++ b/frontend/src/AppBuilder/AppCanvas/Grid/gridUtils.js
@@ -1,7 +1,7 @@
import { useGridStore } from '@/_stores/gridStore';
import { isEmpty } from 'lodash';
import useStore from '@/AppBuilder/_stores/store';
-
+import { getTabId, getSubContainerIdWithSlots } from '../appCanvasUtils';
export function correctBounds(layout, bounds) {
layout = scaleLayouts(layout);
const collidesWith = [];
@@ -414,3 +414,77 @@ export function hideGridLines() {
document.getElementById('real-canvas')?.classList.remove('show-grid');
document.getElementById('real-canvas')?.classList.add('hide-grid');
}
+
+// Track previously active elements for efficient cleanup
+let previousActiveWidgets = null;
+let previousActiveCanvas = null;
+
+export const handleActivateNonDraggingComponents = () => {
+ // Only add non-dragging class to visible components in viewport
+ document.querySelectorAll('.moveable-box:not(.active-target)').forEach((component) => {
+ // Check if element is visible in viewport
+ const rect = component.getBoundingClientRect();
+ const isVisible =
+ rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;
+
+ if (isVisible) {
+ component.classList.add('non-dragging-component');
+ }
+ });
+};
+
+export const handleActivateTargets = (parentId) => {
+ const WIDGETS_WITH_CANVAS_OUTLINE = ['Container', 'Modal', 'Form', 'Listview', 'Kanban'];
+
+ const newParentType = document.getElementById('canvas-' + parentId)?.getAttribute('component-type');
+ let _parentId = parentId;
+ if (newParentType === 'Tabs') {
+ _parentId = getTabId(parentId);
+ } else if (WIDGETS_WITH_CANVAS_OUTLINE.includes(newParentType)) {
+ _parentId = getSubContainerIdWithSlots(parentId);
+ }
+
+ // Clean up previous active elements
+ if (previousActiveWidgets) {
+ previousActiveWidgets.classList.remove('dragging-component-canvas');
+ previousActiveWidgets = null;
+ }
+
+ if (previousActiveCanvas) {
+ previousActiveCanvas.classList.remove('dragging-component-canvas');
+ previousActiveCanvas = null;
+ }
+
+ const parentComponent = document.getElementById(_parentId);
+ if (!parentComponent) return;
+
+ if (WIDGETS_WITH_CANVAS_OUTLINE?.includes(newParentType)) {
+ // If it's multiple canvas in single widget, highlight the specific canvas
+ const canvasElm = document.getElementById('canvas-' + parentId);
+ if (canvasElm) {
+ canvasElm.classList.add('dragging-component-canvas');
+ previousActiveCanvas = canvasElm;
+ }
+ } else {
+ // Otherwise highlight the component box
+ parentComponent.classList.remove('non-dragging-component');
+ parentComponent.classList.add('dragging-component-canvas');
+ previousActiveWidgets = parentComponent;
+ }
+};
+
+export const handleDeactivateTargets = () => {
+ if (previousActiveWidgets) {
+ previousActiveWidgets.classList.remove('dragging-component-canvas');
+ previousActiveWidgets = null;
+ }
+
+ if (previousActiveCanvas) {
+ previousActiveCanvas.classList.remove('dragging-component-canvas');
+ previousActiveCanvas = null;
+ }
+
+ document.querySelectorAll('.non-dragging-component').forEach((component) => {
+ component.classList.remove('non-dragging-component');
+ });
+};
diff --git a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx
index 895697091f..0f1cb3359f 100644
--- a/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx
+++ b/frontend/src/AppBuilder/AppCanvas/WidgetWrapper.jsx
@@ -69,6 +69,7 @@ const WidgetWrapper = memo(
data-id={`${id}`}
id={id}
widgetid={id}
+ component-type={componentType}
style={{
// zIndex: mode === 'view' && widget.component.component == 'Datepicker' ? 2 : null,
...styles,
diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
index 41bc116ec3..8dae9e001c 100644
--- a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
+++ b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js
@@ -690,3 +690,19 @@ export const getParentWidgetFromId = (parentType, parentId) => {
}
return parentType;
};
+
+export const getTabId = (parentId) => {
+ return parentId.split('-').slice(0, -1).join('-');
+};
+
+export const getSubContainerIdWithSlots = (parentId) => {
+ let cleanParentId = parentId;
+ if (parentId) {
+ if (parentId.includes('header')) {
+ cleanParentId = parentId.replace('-header', '');
+ } else if (parentId.includes('footer')) {
+ cleanParentId = parentId.replace('-footer', '');
+ }
+ }
+ return cleanParentId;
+};
diff --git a/frontend/src/AppBuilder/AppCanvas/selecto.scss b/frontend/src/AppBuilder/AppCanvas/selecto.scss
index 9ca8a37f41..5602b35d5a 100644
--- a/frontend/src/AppBuilder/AppCanvas/selecto.scss
+++ b/frontend/src/AppBuilder/AppCanvas/selecto.scss
@@ -3,15 +3,18 @@
}
.main-editor-canvas .widget-target:not(:has(.widget-target:hover)):hover {
- z-index: 4 !important;
-}
-
-.main-editor-canvas .widget-target:has(.nested-target:hover):hover {
- outline: 0px solid #4af;
-}
-
-.main-editor-canvas .nested-target:not(:has(.nested-target:hover)):hover {
outline: 1px solid #4af;
z-index: 4 !important;
}
+.main-editor-canvas .nested-target:not(:has(.nested-target:hover)):hover {
+ // outline: 1px solid #4af;
+ z-index: 4 !important;
+}
+
+// .main-editor-canvas .widget-target:hover {
+// outline: 1px solid #4af;
+// }
+
+
+
From 6a7d72f759c71e60ac1be945e7b7ec5705c89b77 Mon Sep 17 00:00:00 2001
From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Date: Mon, 10 Mar 2025 21:27:31 +0530
Subject: [PATCH 12/12] Adds CSA for forms
---
.../AppBuilder/WidgetManager/widgets/form.js | 18 +++++++++
frontend/src/AppBuilder/Widgets/Form/Form.jsx | 38 +++++++++++++++----
.../src/AppBuilder/Widgets/Form/form.scss | 19 +++++++++-
.../src/Editor/WidgetManager/configs/form.js | 18 +++++++++
.../apps/services/widget-config/form.js | 18 +++++++++
5 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/form.js b/frontend/src/AppBuilder/WidgetManager/widgets/form.js
index 7ab4bd26a6..2d8eb7f0a8 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/form.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/form.js
@@ -362,6 +362,9 @@ export const formConfig = {
exposedVariables: {
data: {},
isValid: true,
+ isVisible: true,
+ isDisabled: false,
+ isLoading: false,
},
actions: [
{
@@ -372,6 +375,21 @@ export const formConfig = {
handle: 'resetForm',
displayName: 'Reset Form',
},
+ {
+ handle: 'setVisibility',
+ displayName: 'Set visibility',
+ params: [{ handle: 'setVisibility', displayName: 'Set Visibility', defaultValue: '{{true}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setDisable',
+ displayName: 'Set Disable',
+ params: [{ handle: 'setDisable', displayName: 'Set Disable', defaultValue: '{{false}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setLoading',
+ displayName: 'Set Loading',
+ params: [{ handle: 'setLoading', displayName: 'Set Loading', defaultValue: '{{false}}', type: 'toggle' }],
+ },
],
definition: {
others: {
diff --git a/frontend/src/AppBuilder/Widgets/Form/Form.jsx b/frontend/src/AppBuilder/Widgets/Form/Form.jsx
index b61d40c194..afeb4cf844 100644
--- a/frontend/src/AppBuilder/Widgets/Form/Form.jsx
+++ b/frontend/src/AppBuilder/Widgets/Form/Form.jsx
@@ -8,6 +8,7 @@ import { onComponentClick, removeFunctionObjects } from '@/_helpers/appUtils';
import { deepClone } from '@/_helpers/utilities/utils.helpers';
import RenderSchema from './RenderSchema';
import useStore from '@/AppBuilder/_stores/store';
+import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables';
import { shallow } from 'zustand/shallow';
import {
CONTAINER_FORM_CANVAS_PADDING,
@@ -55,6 +56,13 @@ export const Form = function Form(props) {
visibility,
disabledState,
} = properties;
+ const { isDisabled, isVisible, isLoading } = useExposeState(
+ properties.loadingState,
+ properties.visibility,
+ properties.disabledState,
+ setExposedVariables,
+ setExposedVariable
+ );
const backgroundColor =
['#fff', '#ffffffff'].includes(styles.backgroundColor) && darkMode ? '#232E3C' : styles.backgroundColor;
const computedStyles = {
@@ -62,7 +70,7 @@ export const Form = function Form(props) {
borderRadius: borderRadius ? parseFloat(borderRadius) : 0,
border: `${SUBCONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`,
height,
- display: visibility ? 'flex' : 'none',
+ display: isVisible ? 'flex' : 'none',
position: 'relative',
boxShadow,
flexDirection: 'column',
@@ -305,17 +313,24 @@ export const Form = function Form(props) {
}}
componentType="Form"
/>
+ {isDisabled && (
+
)}
- {loadingState ? (
-
-
-
-
+ {isLoading ? (
+
) : (
-
+
{!advanced && (
+ {isDisabled && (
+
)}
diff --git a/frontend/src/AppBuilder/Widgets/Form/form.scss b/frontend/src/AppBuilder/Widgets/Form/form.scss
index 88a5ad055e..530e837eb2 100644
--- a/frontend/src/AppBuilder/Widgets/Form/form.scss
+++ b/frontend/src/AppBuilder/Widgets/Form/form.scss
@@ -1,7 +1,7 @@
.wj-form-header {
position: relative;
&::after {
- content: '';
+ content: "";
position: absolute;
bottom: 0;
left: -7px;
@@ -14,7 +14,7 @@
.wj-form-footer {
position: relative;
&::after {
- content: '';
+ content: "";
position: absolute;
top: 0;
left: -7px;
@@ -23,3 +23,18 @@
background-color: var(--border-weak);
}
}
+
+.tj-form-disabled-overlay {
+ /* TODO: Make slot overlays common */
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(255, 255, 255, 0.8);
+ z-index: 1;
+ margin: 0;
+
+ box-sizing: content-box;
+ padding: 4px 0;
+}
diff --git a/frontend/src/Editor/WidgetManager/configs/form.js b/frontend/src/Editor/WidgetManager/configs/form.js
index 7ab4bd26a6..2d8eb7f0a8 100644
--- a/frontend/src/Editor/WidgetManager/configs/form.js
+++ b/frontend/src/Editor/WidgetManager/configs/form.js
@@ -362,6 +362,9 @@ export const formConfig = {
exposedVariables: {
data: {},
isValid: true,
+ isVisible: true,
+ isDisabled: false,
+ isLoading: false,
},
actions: [
{
@@ -372,6 +375,21 @@ export const formConfig = {
handle: 'resetForm',
displayName: 'Reset Form',
},
+ {
+ handle: 'setVisibility',
+ displayName: 'Set visibility',
+ params: [{ handle: 'setVisibility', displayName: 'Set Visibility', defaultValue: '{{true}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setDisable',
+ displayName: 'Set Disable',
+ params: [{ handle: 'setDisable', displayName: 'Set Disable', defaultValue: '{{false}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setLoading',
+ displayName: 'Set Loading',
+ params: [{ handle: 'setLoading', displayName: 'Set Loading', defaultValue: '{{false}}', type: 'toggle' }],
+ },
],
definition: {
others: {
diff --git a/server/src/modules/apps/services/widget-config/form.js b/server/src/modules/apps/services/widget-config/form.js
index 7ab4bd26a6..2d8eb7f0a8 100644
--- a/server/src/modules/apps/services/widget-config/form.js
+++ b/server/src/modules/apps/services/widget-config/form.js
@@ -362,6 +362,9 @@ export const formConfig = {
exposedVariables: {
data: {},
isValid: true,
+ isVisible: true,
+ isDisabled: false,
+ isLoading: false,
},
actions: [
{
@@ -372,6 +375,21 @@ export const formConfig = {
handle: 'resetForm',
displayName: 'Reset Form',
},
+ {
+ handle: 'setVisibility',
+ displayName: 'Set visibility',
+ params: [{ handle: 'setVisibility', displayName: 'Set Visibility', defaultValue: '{{true}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setDisable',
+ displayName: 'Set Disable',
+ params: [{ handle: 'setDisable', displayName: 'Set Disable', defaultValue: '{{false}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setLoading',
+ displayName: 'Set Loading',
+ params: [{ handle: 'setLoading', displayName: 'Set Loading', defaultValue: '{{false}}', type: 'toggle' }],
+ },
],
definition: {
others: {