mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
Enhance widget restriction logic for header and footer slots.
This commit is contained in:
parent
d5287caa2c
commit
4ffced9f4e
5 changed files with 71 additions and 15 deletions
|
|
@ -54,7 +54,11 @@ import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
|
|||
import { useElementGuidelines } from './hooks/useElementGuidelines';
|
||||
import { RIGHT_SIDE_BAR_TAB } from '../../RightSideBar/rightSidebarConstants';
|
||||
import ConfigHandleButton from '@/_components/ConfigHandleButton';
|
||||
import { RESTRICTED_WIDGETS_CONFIG } from '@/AppBuilder/WidgetManager/configs/restrictedWidgetsConfig';
|
||||
import { getDropTargetLabel } from '../appCanvasUtils';
|
||||
import {
|
||||
RESTRICTED_WIDGETS_CONFIG,
|
||||
RESTRICTED_WIDGET_SLOTS_CONFIG,
|
||||
} from '@/AppBuilder/WidgetManager/configs/restrictedWidgetsConfig';
|
||||
|
||||
// Lazy load editor-only component to reduce viewer bundle size
|
||||
const MentionComponentInChat = lazy(() => import('../ConfigHandle/MentionComponentInChat'));
|
||||
|
|
@ -547,11 +551,13 @@ export default function Grid({ gridWidth, currentLayout, mainCanvasWidth }) {
|
|||
|
||||
const parentId = targetSlotId?.length > 36 ? targetSlotId.slice(0, 36) : targetSlotId;
|
||||
const parentWidgetType = getComponentTypeFromId(parentId);
|
||||
const parentSlotType = targetSlotId ? targetSlotId.split('-').pop() : undefined;
|
||||
|
||||
let restrictedWidgetsTobeDropped =
|
||||
RESTRICTED_WIDGETS_CONFIG?.[parentWidgetType]?.filter((widgetType) =>
|
||||
widgetsTypeToBeDropped.includes(widgetType)
|
||||
) || [];
|
||||
[
|
||||
...(RESTRICTED_WIDGETS_CONFIG?.[parentWidgetType] || []),
|
||||
...(['header', 'footer'].includes(parentSlotType) ? RESTRICTED_WIDGET_SLOTS_CONFIG : []),
|
||||
].filter((widgetType) => widgetsTypeToBeDropped.includes(widgetType)) || [];
|
||||
|
||||
// Check nesting depth restrictions for all widget types in NESTING_LEVEL_LIMITS
|
||||
let nestingDepthExceeded = false;
|
||||
|
|
@ -602,7 +608,12 @@ export default function Grid({ gridWidth, currentLayout, mainCanvasWidth }) {
|
|||
} else if (isParentModuleContainer) {
|
||||
toast.error('Modules cannot be edited inside an app');
|
||||
} else if (!isParentChangeAllowed) {
|
||||
toast.error(`${restrictedWidgetsTobeDropped} is not compatible as a child component of ${parentWidgetType}`);
|
||||
toast.error(
|
||||
`${restrictedWidgetsTobeDropped} is not compatible as a child component of ${getDropTargetLabel(
|
||||
parentWidgetType,
|
||||
parentSlotType
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1069,7 +1080,12 @@ export default function Grid({ gridWidth, currentLayout, mainCanvasWidth }) {
|
|||
if (isParentModuleContainer) {
|
||||
toast.error('Modules cannot be edited inside an app');
|
||||
} else if (!isModalToCanvas) {
|
||||
toast.error(`${dragged.widgetType} is not compatible as a child component of ${target.widgetType}`);
|
||||
toast.error(
|
||||
`${dragged.widgetType} is not compatible as a child component of ${getDropTargetLabel(
|
||||
target.widgetType,
|
||||
target.slotType
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -728,7 +728,9 @@ export const updateDashedBordersOnDragResize = (targetId, moveableControlBoxClas
|
|||
|
||||
export const isDroppingRestrictedWidget = (target, dragged) => {
|
||||
const restrictedWidgetsOnTarget = RESTRICTED_WIDGETS_CONFIG?.[target.widgetType] || [];
|
||||
const restrictedWidgetsOnTargetSlot = RESTRICTED_WIDGET_SLOTS_CONFIG?.[target.slotType] || [];
|
||||
const restrictedWidgetsOnTargetSlot = ['header', 'footer'].includes(target.slotType)
|
||||
? RESTRICTED_WIDGET_SLOTS_CONFIG
|
||||
: [];
|
||||
|
||||
const restrictedWidgets = [...restrictedWidgetsOnTarget, ...restrictedWidgetsOnTargetSlot];
|
||||
return restrictedWidgets.includes(dragged.widgetType);
|
||||
|
|
|
|||
|
|
@ -340,6 +340,9 @@ export const getParentWidgetFromId = (parentType, parentId) => {
|
|||
return parentType;
|
||||
};
|
||||
|
||||
export const getDropTargetLabel = (widgetType, slotType) =>
|
||||
slotType === 'header' || slotType === 'footer' ? slotType : widgetType;
|
||||
|
||||
export const getTabId = (parentId) => {
|
||||
return parentId.split('-').slice(0, -1).join('-');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,31 @@ export const RESTRICTED_WIDGETS_CONFIG = {
|
|||
Table: ['Kanban'],
|
||||
};
|
||||
|
||||
export const RESTRICTED_WIDGET_SLOTS_CONFIG = {
|
||||
header: ['Calendar', 'Kanban', 'Table', 'Listview', 'Container', 'Accordion'],
|
||||
footer: ['Calendar', 'Kanban', 'Table', 'Listview', 'Container', 'Accordion'],
|
||||
};
|
||||
export const RESTRICTED_WIDGET_SLOTS_CONFIG = [
|
||||
'Form',
|
||||
'Container',
|
||||
'Listview',
|
||||
'Tabs',
|
||||
'Kanban',
|
||||
'Calendar',
|
||||
'Chart',
|
||||
'Accordion',
|
||||
'Map',
|
||||
'IFrame',
|
||||
'KeyValuePair',
|
||||
'RichTextEditor',
|
||||
'Timeline',
|
||||
'JSONExplorer',
|
||||
'JSONEditor',
|
||||
'Html',
|
||||
'CodeEditor',
|
||||
'Chat',
|
||||
'TreeSelect',
|
||||
'PDF',
|
||||
'Camera',
|
||||
'QrScanner',
|
||||
'Text',
|
||||
'TextArea',
|
||||
'AudioRecorder',
|
||||
'CustomComponent',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
|||
import { cloneDeep, merge, set as lodashSet, isEmpty } from 'lodash';
|
||||
import {
|
||||
computeComponentName,
|
||||
getDropTargetLabel,
|
||||
getAllChildComponents,
|
||||
getParentWidgetFromId,
|
||||
} from '@/AppBuilder/AppCanvas/appCanvasUtils';
|
||||
|
|
@ -19,7 +20,10 @@ import { RIGHT_SIDE_BAR_TAB } from '@/AppBuilder/RightSideBar/rightSidebarConsta
|
|||
import { DEFAULT_COMPONENT_STRUCTURE } from './resolvedSlice';
|
||||
import { savePageChanges } from './pageMenuSlice';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { RESTRICTED_WIDGETS_CONFIG } from '@/AppBuilder/WidgetManager/configs/restrictedWidgetsConfig';
|
||||
import {
|
||||
RESTRICTED_WIDGETS_CONFIG,
|
||||
RESTRICTED_WIDGET_SLOTS_CONFIG,
|
||||
} from '@/AppBuilder/WidgetManager/configs/restrictedWidgetsConfig';
|
||||
import moment from 'moment';
|
||||
import { getDateTimeFormat } from '@/_helpers/appUtils';
|
||||
import { findHighestLevelofSelection } from '@/AppBuilder/AppCanvas/Grid/gridUtils';
|
||||
|
|
@ -1225,10 +1229,16 @@ export const createComponentsSlice = (set, get) => ({
|
|||
const transformedParentId = parentId?.length > 36 ? parentId.slice(0, 36) : parentId;
|
||||
let parentType = getComponentTypeFromId(transformedParentId, moduleId);
|
||||
const parentWidget = getParentWidgetFromId(parentType, parentId);
|
||||
const restrictedWidgets = RESTRICTED_WIDGETS_CONFIG?.[parentWidget] || [];
|
||||
const parentSlotType = parentId ? parentId.split('-').pop() : undefined;
|
||||
const restrictedWidgets = [
|
||||
...(RESTRICTED_WIDGETS_CONFIG?.[parentWidget] || []),
|
||||
...(['header', 'footer'].includes(parentSlotType) ? RESTRICTED_WIDGET_SLOTS_CONFIG : []),
|
||||
];
|
||||
const isParentChangeAllowed = !restrictedWidgets.includes(currentWidget);
|
||||
if (!isParentChangeAllowed) {
|
||||
toast.error(`${currentWidget} is not compatible as a child component of ${parentWidget}`);
|
||||
toast.error(
|
||||
`${currentWidget} is not compatible as a child component of ${getDropTargetLabel(parentWidget, parentSlotType)}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1280,7 +1290,8 @@ export const createComponentsSlice = (set, get) => ({
|
|||
moduleId
|
||||
) === false
|
||||
) {
|
||||
return false;
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
const newComponents = buildComponentDefinition(componentDefinitions, moduleId);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue