mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 08:58:26 +00:00
Merge pull request #11403 from ToolJet/release/app-builder-s-4
Release appbuilder S4
This commit is contained in:
commit
bc102a3e93
69 changed files with 2503 additions and 364 deletions
2
.version
2
.version
|
|
@ -1 +1 @@
|
|||
3.0.5-ce
|
||||
3.1.0-ce
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.0.5-ce
|
||||
3.1.0-ce
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import Passwordinput from './passwordinput.jsx';
|
|||
import Pdf from './pdf.jsx';
|
||||
import Qrscanner from './qrscanner.jsx';
|
||||
import RadioButton from './radio-button.jsx';
|
||||
import RadioButtonV2 from './radiobuttonV2.jsx';
|
||||
import Rangeslider from './rangeslider.jsx';
|
||||
import Rating from './rating.jsx';
|
||||
import Spinner from './spinner.jsx';
|
||||
|
|
@ -140,8 +141,10 @@ const WidgetIcon = (props) => {
|
|||
return <Pdf {...props} />;
|
||||
case 'qrscanner':
|
||||
return <Qrscanner {...props} />;
|
||||
case 'radiobutton':
|
||||
case 'radiobuttonlegacy':
|
||||
return <RadioButton {...props} />;
|
||||
case 'radiobutton':
|
||||
return <RadioButtonV2 {...props} />;
|
||||
case 'rangeslider':
|
||||
return <Rangeslider {...props} />;
|
||||
case 'rating':
|
||||
|
|
|
|||
17
frontend/assets/images/icons/widgets/radiobuttonV2.jsx
Normal file
17
frontend/assets/images/icons/widgets/radiobuttonV2.jsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
|
||||
const RadioButtonV2 = ({ fill = '#D7DBDF', width = 24, className = '', viewBox = '0 0 49 48' }) => (
|
||||
<svg
|
||||
width={width}
|
||||
height={width}
|
||||
viewBox={viewBox}
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path fill={fill} d="M24.889 46c12.15 0 22-9.85 22-22s-9.85-22-22-22-22 9.85-22 22 9.85 22 22 22z"></path>
|
||||
<path fill="#3E63DD" d="M24.889 33a9 9 0 100-18 9 9 0 000 18z"></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default RadioButtonV2;
|
||||
|
|
@ -78,10 +78,6 @@
|
|||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.main-editor-canvas .widget-target:hover .widget-target:hover > .config-handle {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.main-editor-canvas .widget-target:hover .widget-target:hover > .widget-target > .config-handle {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[boxList, currentLayout, gridWidth]
|
||||
);
|
||||
|
||||
if (mode !== 'edit') return null;
|
||||
|
||||
return (
|
||||
|
|
@ -425,6 +426,22 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
document.getElementById('resize-ghost-widget').style.height = `${e.target.clientHeight}px`;
|
||||
}
|
||||
}}
|
||||
onResizeStart={(e) => {
|
||||
if (
|
||||
e.target.id &&
|
||||
useGridStore.getState().resizingComponentId !== e.target.id &&
|
||||
!e.target.classList.contains('delete-icon')
|
||||
) {
|
||||
// When clicked on widget boundary/resizer, select the component
|
||||
setSelectedComponents([e.target.id]);
|
||||
}
|
||||
|
||||
if (!isComponentVisible(e.target.id)) {
|
||||
return false;
|
||||
}
|
||||
useGridStore.getState().actions.setResizingComponentId(e.target.id);
|
||||
e.setMin([gridWidth, 10]);
|
||||
}}
|
||||
onResizeEnd={(e) => {
|
||||
try {
|
||||
useGridStore.getState().actions.setResizingComponentId(null);
|
||||
|
|
@ -491,13 +508,6 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
useGridStore.getState().actions.setDragTarget();
|
||||
toggleCanvasUpdater();
|
||||
}}
|
||||
onResizeStart={(e) => {
|
||||
if (!isComponentVisible(e.target.id)) {
|
||||
return false;
|
||||
}
|
||||
useGridStore.getState().actions.setResizingComponentId(e.target.id);
|
||||
e.setMin([gridWidth, 10]);
|
||||
}}
|
||||
onResizeGroupStart={({ events }) => {
|
||||
const parentElm = events[0].target.closest('.real-canvas');
|
||||
parentElm.classList.add('show-grid');
|
||||
|
|
@ -582,7 +592,12 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
onDragStart={(e) => {
|
||||
e?.moveable?.controlBox?.removeAttribute('data-off-screen');
|
||||
const box = boxList.find((box) => box.id === e.target.id);
|
||||
let isDragOnTableORCalendar = false;
|
||||
|
||||
// This flag indicates whether the drag event originated on a child element within a component
|
||||
// (e.g., inside a Table's columns, Calendar's dates, or Kanban's cards).
|
||||
// When true, it prevents the parent component from being dragged, allowing the inner elements
|
||||
// to handle their own interactions like column resizing or card dragging
|
||||
let isDragOnInnerElement = false;
|
||||
|
||||
/* If the drag or click is on a calender popup draggable interactions are not executed so that popups and other components inside calender popup works.
|
||||
Also user dont need to drag an calender from using popup */
|
||||
|
|
@ -593,20 +608,24 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
/* Checking if the dragged elemenent is a table. If its a table drag is disabled since it will affect column resizing and reordering */
|
||||
if (box?.component?.component === 'Table') {
|
||||
const tableElem = e.target.querySelector('.jet-data-table');
|
||||
isDragOnTableORCalendar = tableElem.contains(e.inputEvent.target);
|
||||
isDragOnInnerElement = tableElem.contains(e.inputEvent.target);
|
||||
}
|
||||
if (box?.component?.component === 'Calendar') {
|
||||
const calenderElem =
|
||||
e.target.querySelector('.rbc-month-view') ||
|
||||
e.target.querySelector('.rbc-time-view') ||
|
||||
e.target.querySelector('.rbc-day-view');
|
||||
isDragOnTableORCalendar = calenderElem.contains(e.inputEvent.target);
|
||||
isDragOnInnerElement = calenderElem.contains(e.inputEvent.target);
|
||||
}
|
||||
|
||||
if (
|
||||
['RangeSlider', 'Container', 'BoundedBox', 'Kanban'].includes(box?.component?.component) ||
|
||||
isDragOnTableORCalendar
|
||||
) {
|
||||
if (box?.component?.component === 'Kanban') {
|
||||
const handleContainers = e.target.querySelectorAll('.handle-container');
|
||||
isDragOnInnerElement = Array.from(handleContainers).some((container) =>
|
||||
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'));
|
||||
if (!isHandle) {
|
||||
|
|
@ -666,7 +685,9 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
let left = e.lastEvent?.translate[0];
|
||||
let top = e.lastEvent?.translate[1];
|
||||
if (
|
||||
['Listview', 'Kanban'].includes(boxList.find((box) => box.id === draggedOverElemId)?.component?.component)
|
||||
['Listview', 'Kanban', 'Container'].includes(
|
||||
boxList.find((box) => box.id === draggedOverElemId)?.component?.component
|
||||
)
|
||||
) {
|
||||
const elemContainer = e.target.closest('.real-canvas');
|
||||
const containerHeight = elemContainer.clientHeight;
|
||||
|
|
@ -683,10 +704,19 @@ export default function Grid({ gridWidth, currentLayout }) {
|
|||
if (draggedOverElemId !== currentParentId) {
|
||||
if (isParentChangeAllowed) {
|
||||
const draggedOverWidget = boxList.find((box) => box.id === draggedOverElemId);
|
||||
|
||||
let parentWidgetType = boxList.find((box) => box.id === draggedOverElemId)?.component?.component;
|
||||
// @TODO - When dropping back to container from canvas, the boxList doesn't have canvas header,
|
||||
// boxList will return null. But we need to tell getMouseDistanceFromParentDiv parentWidgetType is container
|
||||
// As container id is like 'canvas-2375e23765e-123234'
|
||||
if (parentId && !parentWidgetType && draggedOverElemId.includes('-header')) {
|
||||
parentWidgetType = 'Container';
|
||||
}
|
||||
|
||||
let { left: _left, top: _top } = getMouseDistanceFromParentDiv(
|
||||
e,
|
||||
draggedOverWidget?.component?.component === 'Kanban' ? draggedOverElem : draggedOverElemId,
|
||||
boxList.find((box) => box.id === draggedOverElemId)?.component?.component
|
||||
parentWidgetType
|
||||
);
|
||||
left = _left;
|
||||
top = _top;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const shouldAddBoxShadowAndVisibility = [
|
|||
'ToggleSwitchV2',
|
||||
'DropdownV2',
|
||||
'MultiselectV2',
|
||||
'RadioButtonV2',
|
||||
];
|
||||
|
||||
const RenderWidget = ({
|
||||
|
|
|
|||
|
|
@ -61,9 +61,8 @@ export const EditorSelecto = () => {
|
|||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
|
||||
const target = e.inputEvent.target;
|
||||
// This condition is to ensure selection happens only on main app canvas and not on child containers
|
||||
// This condition is to ensure selection happens only on main app canvas and not on subcontainers
|
||||
if (target.getAttribute('component-id') === 'canvas') {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export const CANVAS_WIDTHS = Object.freeze({
|
|||
rightSideBarWidth: 300,
|
||||
});
|
||||
|
||||
export const WIDGETS_WITH_DEFAULT_CHILDREN = ['Listview', 'Tabs', 'Form', 'Kanban'];
|
||||
export const WIDGETS_WITH_DEFAULT_CHILDREN = ['Listview', 'Tabs', 'Form', 'Kanban', 'Container'];
|
||||
|
||||
export const DEFAULT_CANVAS_WIDTH = 1292;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
|||
import { componentTypes } from '../WidgetManager';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { CANVAS_WIDTHS, NO_OF_GRIDS } from './appCanvasConstants';
|
||||
import { CANVAS_WIDTHS, NO_OF_GRIDS, WIDGETS_WITH_DEFAULT_CHILDREN } from './appCanvasConstants';
|
||||
import _ from 'lodash';
|
||||
|
||||
export function snapToGrid(canvasWidth, x, y) {
|
||||
|
|
@ -42,8 +42,6 @@ export const addNewWidgetToTheEditor = (componentType, eventMonitorObject, curre
|
|||
componentData.definition.others.showOnMobile.value = `{{true}}`;
|
||||
}
|
||||
|
||||
const widgetsWithDefaultComponents = ['Listview', 'Tabs', 'Form', 'Kanban'];
|
||||
|
||||
const nonActiveLayout = currentLayout === 'desktop' ? 'mobile' : 'desktop';
|
||||
const newComponent = {
|
||||
id: uuidv4(),
|
||||
|
|
@ -66,7 +64,7 @@ export const addNewWidgetToTheEditor = (componentType, eventMonitorObject, curre
|
|||
height: defaultHeight,
|
||||
},
|
||||
},
|
||||
withDefaultChildren: widgetsWithDefaultComponents.includes(componentData.component),
|
||||
withDefaultChildren: WIDGETS_WITH_DEFAULT_CHILDREN.includes(componentData.component),
|
||||
};
|
||||
|
||||
return newComponent;
|
||||
|
|
@ -136,13 +134,14 @@ export function addChildrenWidgetsToParent(componentType, parentId, currentLayou
|
|||
}
|
||||
|
||||
const nonActiveLayout = currentLayout === 'desktop' ? 'mobile' : 'desktop';
|
||||
const _parent = getParentComponentIdByType(child, parentMeta.component, parentId);
|
||||
|
||||
const newChildComponent = {
|
||||
id: uuidv4(),
|
||||
name: widgetName,
|
||||
component: {
|
||||
...componentData,
|
||||
parent: parentMeta.component === 'Tabs' ? parentId + '-' + tab : parentId,
|
||||
parent: getParentComponentIdByType(child, parentMeta.component, parentId),
|
||||
},
|
||||
layouts: {
|
||||
[currentLayout]: {
|
||||
|
|
@ -193,7 +192,8 @@ export const getAllChildComponents = (allComponents, parentId) => {
|
|||
const isParentTabORCalendar =
|
||||
allComponents[parentId]?.component?.component === 'Tabs' ||
|
||||
allComponents[parentId]?.component?.component === 'Calendar' ||
|
||||
allComponents[parentId]?.component?.component === 'Kanban';
|
||||
allComponents[parentId]?.component?.component === 'Kanban' ||
|
||||
allComponents[parentId]?.component?.component === 'Container';
|
||||
|
||||
if (componentParentId && isParentTabORCalendar) {
|
||||
let childComponent = deepClone(allComponents[componentId]);
|
||||
|
|
@ -336,7 +336,11 @@ const isChildOfTabsOrCalendar = (component, allComponents = [], componentParentI
|
|||
const parentComponent = allComponents?.[parentId];
|
||||
|
||||
if (parentComponent) {
|
||||
return parentComponent.component.component === 'Tabs' || parentComponent.component.component === 'Calendar';
|
||||
return (
|
||||
parentComponent.component.component === 'Tabs' ||
|
||||
parentComponent.component.component === 'Calendar' ||
|
||||
parentComponent.component.component === 'Container'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -457,3 +461,11 @@ export const computeViewerBackgroundColor = (isAppDarkMode, canvasBgColor) => {
|
|||
}
|
||||
return canvasBgColor;
|
||||
};
|
||||
|
||||
export const getParentComponentIdByType = (child, parentComponent, parentId) => {
|
||||
const { tab } = child;
|
||||
|
||||
if (parentComponent === 'Tabs') return `${parentId}-${tab}`;
|
||||
else if (parentComponent === 'Container') return `${parentId}-header`;
|
||||
return parentId;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export const ComponentsManagerTab = ({ darkMode }) => {
|
|||
'MultiselectV2',
|
||||
'RichTextEditor',
|
||||
'Checkbox',
|
||||
'RadioButton',
|
||||
'RadioButtonV2',
|
||||
'Datepicker',
|
||||
'DateRangePicker',
|
||||
'FilePicker',
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export const LEGACY_ITEMS = ['ToggleSwitch', 'DropDown', 'Multiselect'];
|
||||
export const LEGACY_ITEMS = ['ToggleSwitch', 'DropDown', 'Multiselect', 'RadioButton'];
|
||||
|
|
|
|||
|
|
@ -181,22 +181,25 @@ class Chart extends React.Component {
|
|||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
title: 'Options',
|
||||
children: (
|
||||
<>
|
||||
{renderElement(
|
||||
component,
|
||||
componentMeta,
|
||||
paramUpdated,
|
||||
dataQueries,
|
||||
'loadingState',
|
||||
'properties',
|
||||
currentState
|
||||
)}
|
||||
{renderElement(component, componentMeta, paramUpdated, dataQueries, 'showAxes', 'properties', currentState)}
|
||||
{renderElement(
|
||||
items.push({
|
||||
title: 'Options',
|
||||
children: (
|
||||
<>
|
||||
{renderElement(
|
||||
component,
|
||||
componentMeta,
|
||||
paramUpdated,
|
||||
dataQueries,
|
||||
'loadingState',
|
||||
'properties',
|
||||
currentState
|
||||
)}
|
||||
{chartType !== 'pie' &&
|
||||
renderElement(component, componentMeta, paramUpdated, dataQueries, 'showAxes', 'properties', currentState)}
|
||||
{chartType !== 'pie' &&
|
||||
renderElement(
|
||||
component,
|
||||
componentMeta,
|
||||
paramUpdated,
|
||||
|
|
@ -205,10 +208,9 @@ class Chart extends React.Component {
|
|||
'properties',
|
||||
currentState
|
||||
)}
|
||||
</>
|
||||
),
|
||||
});
|
||||
}
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
||||
items.push({
|
||||
title: 'Events',
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { shallow } from 'zustand/shallow';
|
|||
|
||||
const SHOW_ADDITIONAL_ACTIONS = [
|
||||
'Text',
|
||||
'Container',
|
||||
'TextInput',
|
||||
'NumberInput',
|
||||
'PasswordInput',
|
||||
|
|
@ -20,6 +21,7 @@ const SHOW_ADDITIONAL_ACTIONS = [
|
|||
'DropdownV2',
|
||||
'MultiselectV2',
|
||||
'Button',
|
||||
'RichTextEditor',
|
||||
];
|
||||
const PROPERTIES_VS_ACCORDION_TITLE = {
|
||||
Text: 'Data',
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ export const EventManager = ({
|
|||
actionId: 'show-alert',
|
||||
message: 'Hello world!',
|
||||
alertType: 'info',
|
||||
component: eventMetaDefinition.name,
|
||||
...customEventRefs,
|
||||
},
|
||||
eventType: eventSourceType,
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ const NEW_REVAMPED_COMPONENTS = [
|
|||
'Checkbox',
|
||||
'DropdownV2',
|
||||
'MultiselectV2',
|
||||
'RadioButtonV2',
|
||||
'Button',
|
||||
];
|
||||
|
||||
|
|
@ -702,6 +703,7 @@ const GetAccordion = React.memo(
|
|||
|
||||
case 'DropdownV2':
|
||||
case 'MultiselectV2':
|
||||
case 'RadioButtonV2':
|
||||
return <Select {...restProps} />;
|
||||
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export function renderCustomStyles(
|
|||
componentConfig.component == 'Table' ||
|
||||
componentConfig.component == 'DropdownV2' ||
|
||||
componentConfig.component == 'MultiselectV2' ||
|
||||
componentConfig.component == 'RadioButtonV2' ||
|
||||
componentConfig.component == 'Button'
|
||||
) {
|
||||
const paramTypeConfig = componentMeta[paramType] || {};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import React from 'react';
|
|||
import WidgetIcon from '@/../assets/images/icons/widgets';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const LEGACY_WIDGETS = ['ToggleSwitch', 'DropDown', 'Multiselect'];
|
||||
const NEW_WIDGETS = ['ToggleSwitchV2', 'DropdownV2', 'MultiselectV2'];
|
||||
const LEGACY_WIDGETS = ['ToggleSwitch', 'DropDown', 'Multiselect', 'RadioButton'];
|
||||
const NEW_WIDGETS = ['ToggleSwitchV2', 'DropdownV2', 'MultiselectV2', 'RadioButtonV2'];
|
||||
|
||||
export const WidgetBox = ({ component, darkMode }) => {
|
||||
const { t } = useTranslation();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig,
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
@ -67,6 +68,7 @@ export const widgets = [
|
|||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig,
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
|
|||
|
|
@ -132,10 +132,7 @@ export const buttonConfig = {
|
|||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: {
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
|
||||
defaultValue: false,
|
||||
},
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: false },
|
||||
accordian: 'button',
|
||||
},
|
||||
boxShadow: {
|
||||
|
|
|
|||
|
|
@ -15,22 +15,92 @@ export const containerConfig = {
|
|||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
section: 'additionalActions',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
showHeader: {
|
||||
type: 'toggle',
|
||||
displayName: 'Show header',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
headerHeight: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Header height',
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 80 },
|
||||
accordian: 'field',
|
||||
},
|
||||
},
|
||||
defaultChildren: [
|
||||
{
|
||||
componentName: 'Text',
|
||||
layout: {
|
||||
top: 20,
|
||||
left: 1,
|
||||
height: 40,
|
||||
},
|
||||
displayName: 'ContainerText',
|
||||
properties: ['text'],
|
||||
accessorKey: 'text',
|
||||
styles: ['fontWeight', 'textSize', 'textColor'],
|
||||
defaultValue: {
|
||||
text: 'Container title',
|
||||
fontWeight: 'bold',
|
||||
textSize: 16,
|
||||
textColor: '#000',
|
||||
},
|
||||
},
|
||||
],
|
||||
events: {},
|
||||
styles: {
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background color',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#fff',
|
||||
},
|
||||
},
|
||||
headerBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Header',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#fff',
|
||||
},
|
||||
},
|
||||
headerHeight: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Header height',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 80,
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'code',
|
||||
displayName: 'Border radius',
|
||||
|
|
@ -50,40 +120,46 @@ export const containerConfig = {
|
|||
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: {},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
visible: { value: '{{true}}' },
|
||||
loadingState: { value: `{{false}}` },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
backgroundColor: { value: '#fff' },
|
||||
headerBackgroundColor: { value: '#fff' },
|
||||
borderRadius: { value: '4' },
|
||||
borderColor: { value: '#fff' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
headerHeight: { value: '80' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -82,10 +82,7 @@ export const imageConfig = {
|
|||
padding: {
|
||||
type: 'code',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 0,
|
||||
},
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 0 },
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { passinputConfig } from './passwordinput';
|
|||
import { datepickerConfig } from './datepicker';
|
||||
import { checkboxConfig } from './checkbox';
|
||||
import { radiobuttonConfig } from './radiobutton';
|
||||
import { radiobuttonV2Config } from './radioButtonV2';
|
||||
import { toggleswitchConfig } from './toggleswitch';
|
||||
import { toggleSwitchV2Config } from './toggleswitchv2';
|
||||
import { textareaConfig } from './textarea';
|
||||
|
|
@ -65,7 +66,8 @@ export {
|
|||
passinputConfig,
|
||||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonConfig, //!Depreciated
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig, //!Depreciated
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
|
|||
|
|
@ -20,10 +20,7 @@ export const numberinputConfig = {
|
|||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 0,
|
||||
},
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 0 },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
|
|
@ -236,7 +233,7 @@ export const numberinputConfig = {
|
|||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
value: 99,
|
||||
value: 0,
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
|
|
|
|||
295
frontend/src/AppBuilder/WidgetManager/widgets/radioButtonV2.js
Normal file
295
frontend/src/AppBuilder/WidgetManager/widgets/radioButtonV2.js
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
export const radiobuttonV2Config = {
|
||||
name: 'RadioButton',
|
||||
displayName: 'Radio Button',
|
||||
description: 'Select one from multiple choices',
|
||||
component: 'RadioButtonV2',
|
||||
defaultSize: {
|
||||
width: 12,
|
||||
height: 43,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
validation: {
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Select',
|
||||
},
|
||||
accordian: 'Data',
|
||||
},
|
||||
advanced: {
|
||||
type: 'toggle',
|
||||
displayName: 'Dynamic options',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
schema: {
|
||||
type: 'code',
|
||||
displayName: 'Schema',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsLoadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Options loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter tooltip text',
|
||||
},
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onSelectionChange: { displayName: 'On select' },
|
||||
},
|
||||
styles: {
|
||||
labelColor: {
|
||||
type: 'color',
|
||||
displayName: 'Color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: 'Direction',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
labelWidth: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
switchOnBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Checked background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
tip: 'Checked background',
|
||||
tooltipStyle: {},
|
||||
tooltipPlacement: 'bottom',
|
||||
},
|
||||
switchOffBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Unchecked background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
tip: 'Unchecked background',
|
||||
tooltipStyle: {},
|
||||
tooltipPlacement: 'bottom',
|
||||
},
|
||||
handleColor: {
|
||||
type: 'color',
|
||||
displayName: 'Handle color',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
optionsTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'selectOption',
|
||||
displayName: 'Select option',
|
||||
params: [{ handle: 'option', displayName: 'Option' }],
|
||||
},
|
||||
{
|
||||
handle: 'deselectOption',
|
||||
displayName: 'Deselect option',
|
||||
params: [{ handle: 'option', displayName: 'Option' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
label: 'Select',
|
||||
},
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: { value: 'Select' },
|
||||
value: { value: '{{"2"}}' },
|
||||
advanced: { value: `{{false}}` },
|
||||
options: {
|
||||
value: [
|
||||
{
|
||||
label: 'option1',
|
||||
value: '1',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: false },
|
||||
},
|
||||
{
|
||||
label: 'option2',
|
||||
value: '2',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: true },
|
||||
},
|
||||
{
|
||||
label: 'option3',
|
||||
value: '3',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
optionsLoadingState: { value: '{{false}}' },
|
||||
optionVisibility: { value: '{{[true, true, true]}}' },
|
||||
optionDisable: { value: '{{[false, false, false]}}' },
|
||||
schema: {
|
||||
value:
|
||||
"{{[\t{label: 'option1',value: '1',disable: false,visible: true,default: true},{label: 'option2',value: '2',disable: false,visible: true},{label: 'option3',value: '3',disable: false,visible: true}\t]}}",
|
||||
},
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
labelColor: { value: '#11181C' },
|
||||
direction: { value: 'left' },
|
||||
alignment: { value: 'side' },
|
||||
auto: { value: '{{false}}' },
|
||||
labelWidth: { value: '20' },
|
||||
borderColor: { value: '#FFFFFF' },
|
||||
switchOffBackgroundColor: { value: '#FFFFFF' },
|
||||
switchOnBackgroundColor: { value: '#4368E3' },
|
||||
handleColor: { value: '#FFFFFF' },
|
||||
optionsTextColor: { value: '#11181C' },
|
||||
padding: { value: 'default' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
export const radiobuttonConfig = {
|
||||
name: 'RadioButton',
|
||||
displayName: 'Radio Button',
|
||||
name: 'RadioButtonLegacy',
|
||||
displayName: 'Radio Button (Legacy)',
|
||||
description: 'Select one from multiple choices',
|
||||
component: 'RadioButton',
|
||||
defaultSize: {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,15 @@ export const richtextareaConfig = {
|
|||
defaultValue: 'Default text',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Show loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
section: 'additionalActions',
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
|
|
@ -55,6 +64,28 @@ export const richtextareaConfig = {
|
|||
exposedVariables: {
|
||||
value: '',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set value',
|
||||
params: [{ handle: 'value', displayName: 'Value', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
|
|
@ -63,6 +94,7 @@ export const richtextareaConfig = {
|
|||
properties: {
|
||||
placeholder: { value: 'Placeholder text' },
|
||||
defaultValue: { value: '' },
|
||||
loadingState: { value: `{{false}}` },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ export const tableConfig = {
|
|||
onCellValueChanged: { displayName: 'Cell value changed' },
|
||||
onFilterChanged: { displayName: 'Filter changed' },
|
||||
onNewRowsAdded: { displayName: 'Add new rows' },
|
||||
onTableDataDownload: { displayName: 'Download data' },
|
||||
},
|
||||
styles: {
|
||||
textColor: {
|
||||
|
|
@ -310,6 +311,16 @@ export const tableConfig = {
|
|||
{ displayName: 'Wrap', value: 'wrap' },
|
||||
],
|
||||
},
|
||||
headerCasing: {
|
||||
type: 'switch',
|
||||
displayName: 'Header casing',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Data',
|
||||
options: [
|
||||
{ displayName: 'AA', value: 'uppercase' },
|
||||
{ displayName: 'As typed', value: 'none' },
|
||||
],
|
||||
},
|
||||
tableType: {
|
||||
type: 'select',
|
||||
displayName: 'Row style',
|
||||
|
|
@ -529,6 +540,7 @@ export const tableConfig = {
|
|||
value: [
|
||||
{
|
||||
name: 'id',
|
||||
key: 'id',
|
||||
id: 'e3ecbf7fa52c4d7210a93edb8f43776267a489bad52bd108be9588f790126737',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -548,6 +560,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'name',
|
||||
key: 'name',
|
||||
id: '5d2a3744a006388aadd012fcc15cc0dbcb5f9130e0fbb64c558561c97118754a',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -556,6 +569,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'email',
|
||||
key: 'email',
|
||||
id: 'afc9a5091750a1bd4760e38760de3b4be11a43452ae8ae07ce2eebc569fe9a7f',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -564,6 +578,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'date',
|
||||
key: 'date',
|
||||
id: '27b75c8af9d34d1eaa1f9bb7f8f9f7b0abf1823e799748c8bb57e74f53b2c1dc',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -576,6 +591,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'mobile_number',
|
||||
key: 'mobile_number',
|
||||
id: '9c2e3c40572a4aefb8e179ee39a0e1ac9dc2b2e6634be56e1c05be13c3d1de56',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -652,6 +668,7 @@ export const tableConfig = {
|
|||
styles: {
|
||||
textColor: { value: '#000' },
|
||||
columnHeaderWrap: { value: 'fixed' },
|
||||
headerCasing: { value: 'uppercase' },
|
||||
actionButtonRadius: { value: '0' },
|
||||
cellSize: { value: 'regular' },
|
||||
borderRadius: { value: '8' },
|
||||
|
|
|
|||
|
|
@ -1,37 +1,99 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { Container as ContainerComponent } from '@/AppBuilder/AppCanvas/Container';
|
||||
import Spinner from '@/_ui/Spinner';
|
||||
import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables';
|
||||
|
||||
export const Container = ({ id, properties, styles, darkMode, height, width }) => {
|
||||
const { visibility, disabledState, borderRadius, borderColor, boxShadow } = styles;
|
||||
const bgColor = useMemo(() => {
|
||||
export const Container = ({
|
||||
id,
|
||||
properties,
|
||||
styles,
|
||||
darkMode,
|
||||
height,
|
||||
width,
|
||||
setExposedVariables,
|
||||
setExposedVariable,
|
||||
}) => {
|
||||
const { isDisabled, isVisible, isLoading } = useExposeState(
|
||||
properties.loadingState,
|
||||
properties.visibility,
|
||||
properties.disabledState,
|
||||
setExposedVariables,
|
||||
setExposedVariable
|
||||
);
|
||||
|
||||
const { borderRadius, borderColor, boxShadow, headerHeight = 80 } = styles;
|
||||
const contentBgColor = useMemo(() => {
|
||||
return {
|
||||
backgroundColor:
|
||||
['#fff', '#ffffffff'].includes(styles.backgroundColor) && darkMode ? '#232E3C' : styles.backgroundColor,
|
||||
};
|
||||
}, [styles.backgroundColor, darkMode]);
|
||||
|
||||
const headerBgColor = useMemo(() => {
|
||||
return {
|
||||
backgroundColor:
|
||||
['#fff', '#ffffffff'].includes(styles.headerBackgroundColor) && darkMode
|
||||
? '#232E3C'
|
||||
: styles.headerBackgroundColor,
|
||||
};
|
||||
}, [styles.headerBackgroundColor, darkMode]);
|
||||
|
||||
const computedStyles = {
|
||||
backgroundColor: bgColor.backgroundColor,
|
||||
backgroundColor: contentBgColor.backgroundColor,
|
||||
borderRadius: borderRadius ? parseFloat(borderRadius) : 0,
|
||||
border: `1px solid ${borderColor}`,
|
||||
height,
|
||||
display: visibility ? 'flex' : 'none',
|
||||
display: isVisible ? 'flex' : 'none',
|
||||
overflow: 'hidden auto',
|
||||
position: 'relative',
|
||||
boxShadow,
|
||||
};
|
||||
|
||||
const computedHeaderStyles = {
|
||||
...headerBgColor,
|
||||
height: `${headerHeight}px`,
|
||||
flexShrink: 0,
|
||||
flexGrow: 0,
|
||||
borderBottom: `1px solid var(--border-weak)`,
|
||||
};
|
||||
|
||||
const computedContentStyles = {
|
||||
...contentBgColor,
|
||||
flex: 1,
|
||||
overflow: 'auto',
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`jet-container ${properties.loadingState && 'jet-container-loading'}`}
|
||||
className={`jet-container tw-flex tw-flex-col ${isLoading ? 'jet-container-loading' : ''} ${
|
||||
properties.showHeader && 'jet-container--with-header'
|
||||
}`}
|
||||
id={id}
|
||||
data-disabled={disabledState}
|
||||
data-disabled={isDisabled}
|
||||
style={computedStyles}
|
||||
>
|
||||
{properties.loadingState ? (
|
||||
{isLoading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<ContainerComponent id={id} styles={bgColor} canvasHeight={height} canvasWidth={width} darkMode={darkMode} />
|
||||
<>
|
||||
{properties.showHeader && (
|
||||
<ContainerComponent
|
||||
id={`${id}-header`}
|
||||
styles={computedHeaderStyles}
|
||||
canvasHeight={headerHeight / 10}
|
||||
canvasWidth={width}
|
||||
allowContainerSelect={true}
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
)}
|
||||
<ContainerComponent
|
||||
id={id}
|
||||
styles={computedContentStyles}
|
||||
canvasHeight={height}
|
||||
canvasWidth={width}
|
||||
darkMode={darkMode}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -290,8 +290,19 @@ const Component = ({ children, ...restProps }) => {
|
|||
} = restProps['modalProps'];
|
||||
|
||||
const setSelectedComponentAsModal = useStore((state) => state.setSelectedComponentAsModal, shallow);
|
||||
|
||||
// When the modal body is clicked capture it and use the callback to set the selected component as modal
|
||||
const handleModalBodyClick = (event) => {
|
||||
const clickedComponentId = event.target.getAttribute('component-id');
|
||||
|
||||
// Check if the clicked element is part of the modal canvas & same widget with id
|
||||
if (id === clickedComponentId) {
|
||||
setSelectedComponentAsModal(id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<BootstrapModal {...restProps}>
|
||||
<BootstrapModal {...restProps} onClick={handleModalBodyClick}>
|
||||
{showConfigHandler && (
|
||||
<ConfigHandle
|
||||
id={id}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ export const Footer = React.memo(
|
|||
showAddNewRowPopup,
|
||||
downlaodPopover,
|
||||
getToggleHideAllColumnsProps,
|
||||
isDownloadTableDataEventAssociated,
|
||||
}) => {
|
||||
function hideColumnsPopover() {
|
||||
return (
|
||||
|
|
@ -223,32 +224,57 @@ export const Footer = React.memo(
|
|||
)}
|
||||
{!loadingState && showDownloadButton && (
|
||||
<div>
|
||||
<Tooltip id="tooltip-for-download" className="tooltip" />
|
||||
<OverlayTriggerComponent
|
||||
trigger="click"
|
||||
overlay={downlaodPopover()}
|
||||
rootClose={true}
|
||||
placement={'top-end'}
|
||||
>
|
||||
<ButtonSolid
|
||||
variant="ghostBlack"
|
||||
className={`tj-text-xsm `}
|
||||
customStyles={{
|
||||
minWidth: '32px',
|
||||
}}
|
||||
leftIcon="filedownload"
|
||||
fill={`var(--icons-default)`}
|
||||
iconWidth="16"
|
||||
size="md"
|
||||
data-tooltip-id="tooltip-for-download"
|
||||
data-tooltip-content="Download"
|
||||
onClick={(e) => {
|
||||
if (document.activeElement === e.currentTarget) {
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
></ButtonSolid>
|
||||
</OverlayTriggerComponent>
|
||||
{
|
||||
// if server side pagination is enabled and download event is associated with the table, then directly fire download event without displaying popover
|
||||
isDownloadTableDataEventAssociated && !clientSidePagination ? (
|
||||
<>
|
||||
<Tooltip id="tooltip-for-download-serverside-pagingation" className="tooltip" />
|
||||
<ButtonSolid
|
||||
variant="ghostBlack"
|
||||
className={`tj-text-xsm `}
|
||||
customStyles={{
|
||||
minWidth: '32px',
|
||||
}}
|
||||
leftIcon="filedownload"
|
||||
fill={`var(--icons-default)`}
|
||||
iconWidth="16"
|
||||
size="md"
|
||||
data-tooltip-id="tooltip-for-download-serverside-pagingation"
|
||||
data-tooltip-content="Download"
|
||||
onClick={() => fireEvent('onTableDataDownload')}
|
||||
></ButtonSolid>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Tooltip id="tooltip-for-download" className="tooltip" />
|
||||
<OverlayTriggerComponent
|
||||
trigger="click"
|
||||
overlay={downlaodPopover()}
|
||||
rootClose={true}
|
||||
placement={'top-end'}
|
||||
>
|
||||
<ButtonSolid
|
||||
variant="ghostBlack"
|
||||
className={`tj-text-xsm `}
|
||||
customStyles={{
|
||||
minWidth: '32px',
|
||||
}}
|
||||
leftIcon="filedownload"
|
||||
fill={`var(--icons-default)`}
|
||||
iconWidth="16"
|
||||
size="md"
|
||||
data-tooltip-id="tooltip-for-download"
|
||||
data-tooltip-content="Download"
|
||||
onClick={(e) => {
|
||||
if (document.activeElement === e.currentTarget) {
|
||||
e.currentTarget.blur();
|
||||
}
|
||||
}}
|
||||
></ButtonSolid>
|
||||
</OverlayTriggerComponent>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
{!loadingState && !hideColumnSelectorButton && (
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const TableHeader = ({
|
|||
columnHeaderWrap,
|
||||
setResizingColumnId,
|
||||
resizingColumnId,
|
||||
headerCasing,
|
||||
}) => {
|
||||
const calculateWidthOfActionColumnHeader = (position) => {
|
||||
let totalWidth = null;
|
||||
|
|
@ -193,6 +194,7 @@ export const TableHeader = ({
|
|||
'text-truncate': getResolvedValue(columnHeaderWrap) === 'fixed',
|
||||
'wrap-wrapper': getResolvedValue(columnHeaderWrap) === 'wrap',
|
||||
})}
|
||||
style={{ textTransform: headerCasing === 'uppercase' ? 'uppercase' : 'none' }}
|
||||
>
|
||||
{column.render('Header')}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ export const Table = React.memo(
|
|||
borderColor,
|
||||
isMaxRowHeightAuto,
|
||||
columnHeaderWrap,
|
||||
headerCasing,
|
||||
} = loadPropertiesAndStyles(properties, styles, darkMode);
|
||||
const updatedDataReference = useRef([]);
|
||||
const preSelectRow = useRef(false);
|
||||
|
|
@ -153,6 +154,7 @@ export const Table = React.memo(
|
|||
const [tableDetails, dispatch] = useReducer(reducer, initialState());
|
||||
const [hoverAdded, setHoverAdded] = useState(false);
|
||||
const [generatedColumn, setGeneratedColumn] = useState([]);
|
||||
const [isDownloadTableDataEventAssociated, setIsDownloadTableDataEventAssociated] = useState(false);
|
||||
|
||||
const mergeToTableDetails = useCallback((payload) => dispatch(reducerActions.mergeToTableDetails(payload)), []);
|
||||
const mergeToFilterDetails = (payload) => dispatch(reducerActions.mergeToFilterDetails(payload));
|
||||
|
|
@ -174,6 +176,9 @@ export const Table = React.memo(
|
|||
useEffect(() => mergeToTableDetails({ columnProperties: properties?.columns }), [properties?.columns]);
|
||||
|
||||
useEffect(() => {
|
||||
const isDownloadTableDataEventAssociated = tableEvents.some((event) => event?.name === 'onTableDataDownload');
|
||||
if (isDownloadTableDataEventAssociated) setIsDownloadTableDataEventAssociated(true);
|
||||
else setIsDownloadTableDataEventAssociated(false);
|
||||
const hoverEvent = tableEvents?.find(({ event }) => {
|
||||
return event?.eventId == 'onRowHovered';
|
||||
});
|
||||
|
|
@ -1096,6 +1101,7 @@ export const Table = React.memo(
|
|||
columnHeaderWrap={columnHeaderWrap}
|
||||
setResizingColumnId={setResizingColumnId}
|
||||
resizingColumnId={resizingColumnId}
|
||||
headerCasing={headerCasing}
|
||||
/>
|
||||
{page.length > 0 && !loadingState && (
|
||||
<tbody
|
||||
|
|
@ -1165,6 +1171,7 @@ export const Table = React.memo(
|
|||
{loadingState ? <LoadingState /> : page.length === 0 ? <EmptyState /> : null}
|
||||
</div>
|
||||
<Footer
|
||||
isDownloadTableDataEventAssociated={isDownloadTableDataEventAssociated}
|
||||
enablePagination={enablePagination}
|
||||
tableDetails={tableDetails}
|
||||
loadingState={loadingState}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ export default function loadPropertiesAndStyles(properties, styles, darkMode) {
|
|||
const contentWrapProperty = styles?.contentWrap ?? true;
|
||||
const borderColor = styles?.borderColor ?? 'var(--borders-weak-disabled)';
|
||||
const columnHeaderWrap = styles?.columnHeaderWrap ?? 'fixed';
|
||||
const headerCasing = styles?.headerCasing ?? 'uppercase';
|
||||
|
||||
return {
|
||||
color,
|
||||
|
|
@ -122,5 +123,6 @@ export default function loadPropertiesAndStyles(properties, styles, darkMode) {
|
|||
boxShadow,
|
||||
borderColor,
|
||||
columnHeaderWrap,
|
||||
headerCasing,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import { Map as MapComponent } from '@/Editor/Components/Map/Map';
|
|||
import { QrScanner } from '@/Editor/Components/QrScanner/QrScanner';
|
||||
import { ToggleSwitch } from '@/Editor/Components/Toggle';
|
||||
import { ToggleSwitchV2 } from '@/Editor/Components/ToggleV2';
|
||||
|
||||
import { RadioButton } from '@/Editor/Components/RadioButton';
|
||||
import { RadioButtonV2 } from '@/Editor/Components/RadioButtonV2/RadioButtonV2';
|
||||
import { StarRating } from '@/Editor/Components/StarRating';
|
||||
import { Divider } from '@/Editor/Components/Divider';
|
||||
import { FilePicker } from '@/Editor/Components/FilePicker';
|
||||
|
|
@ -106,6 +106,7 @@ export const AllComponents = {
|
|||
QrScanner,
|
||||
ToggleSwitch,
|
||||
RadioButton,
|
||||
RadioButtonV2,
|
||||
StarRating,
|
||||
Divider,
|
||||
FilePicker,
|
||||
|
|
|
|||
51
frontend/src/AppBuilder/_hooks/useExposeVariables.js
Normal file
51
frontend/src/AppBuilder/_hooks/useExposeVariables.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useExposeState = (loadingState, visibleState, disabledState, setExposedVariables, setExposedVariable) => {
|
||||
const [isDisabled, setDisable] = useState(disabledState || false);
|
||||
const [isVisible, setVisibility] = useState(visibleState || true);
|
||||
const [isLoading, setLoading] = useState(loadingState || false);
|
||||
|
||||
// Effect to conditionally update state from properties passed to widget
|
||||
useEffect(() => {
|
||||
setDisable(disabledState);
|
||||
}, [disabledState]);
|
||||
|
||||
useEffect(() => {
|
||||
setVisibility(visibleState);
|
||||
}, [visibleState]);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(loadingState);
|
||||
}, [loadingState]);
|
||||
|
||||
// exposed variables with state and async setters, happens on first time load
|
||||
useEffect(() => {
|
||||
setExposedVariables({
|
||||
setDisable: async (value) => setDisable(value),
|
||||
setVisibility: async (value) => setVisibility(value),
|
||||
setLoading: async (value) => setLoading(value),
|
||||
});
|
||||
}, [setExposedVariables]);
|
||||
|
||||
//Side effect to state variables, these will run after the state is set and the values will be exposed
|
||||
useEffect(() => {
|
||||
setExposedVariable('isDisabled', isDisabled);
|
||||
}, [isDisabled, setExposedVariable]);
|
||||
|
||||
useEffect(() => {
|
||||
setExposedVariable('isVisible', isVisible);
|
||||
}, [isVisible, setExposedVariable]);
|
||||
|
||||
useEffect(() => {
|
||||
setExposedVariable('isLoading', isLoading);
|
||||
}, [isLoading, setExposedVariable]);
|
||||
|
||||
return {
|
||||
isDisabled,
|
||||
setDisable,
|
||||
isVisible,
|
||||
setVisibility,
|
||||
isLoading,
|
||||
setLoading,
|
||||
};
|
||||
};
|
||||
|
|
@ -1822,7 +1822,11 @@ export const createComponentsSlice = (set, get) => ({
|
|||
const label = componentDefinition?.component?.definition?.properties?.label;
|
||||
const getAllExposedValues = get().getAllExposedValues;
|
||||
// Early return for non input components
|
||||
if (!['TextInput', 'PasswordInput', 'NumberInput', 'DropdownV2', 'MultiselectV2'].includes(componentType)) {
|
||||
if (
|
||||
!['TextInput', 'PasswordInput', 'NumberInput', 'DropdownV2', 'MultiselectV2', 'RadioButtonV2'].includes(
|
||||
componentType
|
||||
)
|
||||
) {
|
||||
return layoutData?.height;
|
||||
}
|
||||
const { alignment = { value: null }, width = { value: null }, auto = { value: null } } = stylesDefinition ?? {};
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ export const createDebuggerSlice = (set, get) => ({
|
|||
componentId: id,
|
||||
},
|
||||
logLevel: 'error',
|
||||
errorTarget: 'Component Property',
|
||||
timestamp: moment().toISOString(),
|
||||
}));
|
||||
|
||||
|
|
@ -191,6 +192,7 @@ export const createDebuggerSlice = (set, get) => ({
|
|||
effectiveProperty: { [property]: defaultValue },
|
||||
componentId,
|
||||
},
|
||||
errorTarget: 'Component Property',
|
||||
logLevel: 'error',
|
||||
timestamp: moment().toISOString(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import generateFile from '@/_lib/generate-file';
|
|||
import urlJoin from 'url-join';
|
||||
import { useCallback } from 'react';
|
||||
import { navigate } from '@/AppBuilder/_utils/misc';
|
||||
import moment from 'moment';
|
||||
|
||||
// To unsubscribe from the changes when no longer needed
|
||||
// unsubscribe();
|
||||
|
|
@ -211,32 +212,46 @@ export const createEventsSlice = (set, get) => ({
|
|||
state.eventsSlice.module[moduleId].events = newEvents;
|
||||
});
|
||||
},
|
||||
setTablePageIndex: (tableId, index = 1) => {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
if (_.isEmpty(tableId)) {
|
||||
console.log('No table is associated with this event.');
|
||||
setTablePageIndex: (tableId, index, eventObj) => {
|
||||
try {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
if (typeof index !== 'number' && index !== undefined) {
|
||||
throw new Error('Invalid page index.');
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(tableId);
|
||||
if (!exposedValue) {
|
||||
throw new Error('No table is associated with this event.');
|
||||
}
|
||||
exposedValue.setPage(index);
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('set_table_page_index', 'set-table-page-index', error, eventObj, {
|
||||
eventId: eventObj.eventType,
|
||||
});
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(tableId);
|
||||
if (!exposedValue) {
|
||||
console.log('No table is associated with this event.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
exposedValue.setPage(index);
|
||||
return Promise.resolve();
|
||||
},
|
||||
showModal: (modal, show) => {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
const modalId = modal?.id ?? modal;
|
||||
console.log('modalId', modalId);
|
||||
if (_.isEmpty(modalId)) {
|
||||
console.log('No modal is associated with this event.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(modalId);
|
||||
show ? exposedValue.open() : exposedValue.close();
|
||||
showModal: (modal, show, eventObj) => {
|
||||
try {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
const modalId = modal?.id ?? modal;
|
||||
if (_.isEmpty(modalId)) {
|
||||
throw new Error('No modal is associated with this event.');
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(modalId);
|
||||
show ? exposedValue.open() : exposedValue.close();
|
||||
|
||||
return Promise.resolve();
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError(
|
||||
show ? 'show_modal' : 'close_modal',
|
||||
show ? 'show-modal' : 'close_modal',
|
||||
error,
|
||||
eventObj,
|
||||
{
|
||||
eventId: eventObj.eventType,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
handleEvent: (eventName, events, options, moduleId = 'canvas') => {
|
||||
const latestEvents = get().eventsSlice.getModuleEvents(moduleId);
|
||||
|
|
@ -361,6 +376,7 @@ export const createEventsSlice = (set, get) => ({
|
|||
'onSubmit',
|
||||
'onInvalid',
|
||||
'onNewRowsAdded',
|
||||
'onTableDataDownload',
|
||||
].includes(eventName)
|
||||
) {
|
||||
executeActionsForEventId(eventName, events, mode, customVariables);
|
||||
|
|
@ -381,13 +397,84 @@ export const createEventsSlice = (set, get) => ({
|
|||
?.sort((a, b) => a.index - b.index);
|
||||
|
||||
for (const event of filteredEvents) {
|
||||
await get().eventsSlice.executeAction(event.event, mode, customVariables);
|
||||
await get().eventsSlice.executeAction(event, mode, customVariables);
|
||||
}
|
||||
},
|
||||
executeAction: debounce(async (event, mode, customVariables = {}) => {
|
||||
logError(errorType, errorKind, error, eventObj = '', options = {}, logLevel) {
|
||||
const { event = eventObj } = eventObj;
|
||||
const pages = get().modules.canvas.pages;
|
||||
const currentPageId = get().currentPageId;
|
||||
const currentPage = pages.find((page) => page.id === currentPageId);
|
||||
const componentIdMapping = get().modules['canvas'].componentNameIdMapping;
|
||||
const componentName = Object.keys(componentIdMapping).find(
|
||||
(key) => componentIdMapping[key] === eventObj?.sourceId
|
||||
);
|
||||
const componentId = eventObj?.sourceId;
|
||||
|
||||
const getSource = () => {
|
||||
if (eventObj.eventType) {
|
||||
return eventObj.eventType === 'data_query' ? 'query' : eventObj.eventType;
|
||||
}
|
||||
|
||||
const sourceMap = {
|
||||
onDataQueryFailure: 'query',
|
||||
onDataQuerySuccess: 'query',
|
||||
onPageLoad: 'page',
|
||||
};
|
||||
|
||||
return sourceMap[event.eventId] || 'component';
|
||||
};
|
||||
|
||||
const getQueryName = () => {
|
||||
const queries = get().dataQuery.queries.modules.canvas;
|
||||
return queries.find((query) => query.id === eventObj?.sourceId || '')?.name || '';
|
||||
};
|
||||
|
||||
const constructErrorHeader = () => {
|
||||
const source = getSource();
|
||||
const pageName = currentPage.name;
|
||||
|
||||
const headerMap = {
|
||||
component: `[Page ${pageName}] [Component ${componentName}] [Event ${event?.eventId}] [Action ${event.actionId}]`,
|
||||
page: `[Page ${pageName}] [Event ${event.eventId}] [Action ${event.actionId}]`,
|
||||
query: `[Query ${getQueryName()}] [Event ${event.eventId}] [Action ${event.actionId}]`,
|
||||
};
|
||||
|
||||
return headerMap[source] || '';
|
||||
};
|
||||
|
||||
const constructErrorTarget = () => {
|
||||
const source = getSource();
|
||||
|
||||
const errorTargetMap = {
|
||||
page: 'Event Errors with page',
|
||||
component: 'Component Event',
|
||||
query: 'Event Errors with query',
|
||||
};
|
||||
|
||||
return errorTargetMap[source];
|
||||
};
|
||||
useStore.getState().debugger.log({
|
||||
logLevel: logLevel ? logLevel : 'error',
|
||||
type: errorType ? errorType : 'event',
|
||||
kind: errorKind,
|
||||
key: constructErrorHeader(),
|
||||
error: {
|
||||
message: error.message,
|
||||
description: JSON.stringify(error.message, null, 2),
|
||||
...(event.component && componentId && { componentId: componentId }),
|
||||
},
|
||||
errorTarget: constructErrorTarget(),
|
||||
options: options,
|
||||
strace: 'app_level',
|
||||
timestamp: moment().toISOString(),
|
||||
});
|
||||
},
|
||||
executeAction: debounce(async (eventObj, mode, customVariables = {}) => {
|
||||
const { event = eventObj } = eventObj;
|
||||
const { getExposedValueOfComponent, getResolvedValue } = get();
|
||||
|
||||
if (event.runOnlyIf) {
|
||||
if (event?.runOnlyIf) {
|
||||
const shouldRun = getResolvedValue(event.runOnlyIf, customVariables);
|
||||
if (!shouldRun) {
|
||||
return false;
|
||||
|
|
@ -418,23 +505,37 @@ export const createEventsSlice = (set, get) => ({
|
|||
return Promise.resolve();
|
||||
}
|
||||
case 'run-query': {
|
||||
const { queryId, queryName } = event;
|
||||
const params = event['parameters'];
|
||||
const resolvedParams = {};
|
||||
if (params) {
|
||||
Object.keys(params).map((param) => (resolvedParams[param] = getResolvedValue(params[param], undefined)));
|
||||
try {
|
||||
const { queryId, queryName, component, eventId } = event;
|
||||
const params = event['parameters'];
|
||||
if (!queryId && !queryName) {
|
||||
throw new Error('No query selected');
|
||||
}
|
||||
const resolvedParams = {};
|
||||
if (params) {
|
||||
Object.keys(params).map(
|
||||
(param) => (resolvedParams[param] = getResolvedValue(params[param], undefined))
|
||||
);
|
||||
}
|
||||
// !Todo tackle confirm query part once done
|
||||
return get().queryPanel.runQuery(
|
||||
queryId,
|
||||
queryName,
|
||||
undefined,
|
||||
undefined,
|
||||
resolvedParams,
|
||||
component,
|
||||
eventId,
|
||||
false,
|
||||
false,
|
||||
'canvas'
|
||||
);
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('run_query', 'run-query', error, eventObj, {
|
||||
eventId: event.eventId,
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
// !Todo tackle confirm query part once done
|
||||
return get().queryPanel.runQuery(
|
||||
queryId,
|
||||
queryName,
|
||||
undefined,
|
||||
undefined,
|
||||
resolvedParams,
|
||||
false,
|
||||
false,
|
||||
'canvas'
|
||||
);
|
||||
}
|
||||
case 'logout': {
|
||||
return logoutAction();
|
||||
|
|
@ -447,39 +548,47 @@ export const createEventsSlice = (set, get) => ({
|
|||
return Promise.resolve();
|
||||
}
|
||||
case 'go-to-app': {
|
||||
const resolvedValue = getResolvedValue(event.slug, customVariables);
|
||||
const slug = resolvedValue;
|
||||
const queryParams = event.queryParams?.reduce(
|
||||
(result, queryParam) => ({
|
||||
...result,
|
||||
...{
|
||||
[getResolvedValue(queryParam[0])]: getResolvedValue(queryParam[1], undefined, customVariables),
|
||||
},
|
||||
}),
|
||||
{}
|
||||
);
|
||||
let url = `/applications/${slug}`;
|
||||
|
||||
if (queryParams) {
|
||||
const queryPart = serializeNestedObjectToQueryParams(queryParams);
|
||||
|
||||
if (queryPart.length > 0) url = url + `?${queryPart}`;
|
||||
}
|
||||
if (mode === 'view') {
|
||||
navigate(url);
|
||||
} else {
|
||||
if (confirm('The app will be opened in a new tab as the action is triggered from the editor.')) {
|
||||
window.open(urlJoin(window.public_config?.TOOLJET_HOST, url));
|
||||
try {
|
||||
if (!event.slug) {
|
||||
throw new Error('No application slug provided');
|
||||
}
|
||||
const resolvedValue = getResolvedValue(event.slug, customVariables);
|
||||
const slug = resolvedValue;
|
||||
const queryParams = event.queryParams?.reduce(
|
||||
(result, queryParam) => ({
|
||||
...result,
|
||||
...{
|
||||
[getResolvedValue(queryParam[0])]: getResolvedValue(queryParam[1], undefined, customVariables),
|
||||
},
|
||||
}),
|
||||
{}
|
||||
);
|
||||
let url = `/applications/${slug}`;
|
||||
|
||||
if (queryParams) {
|
||||
const queryPart = serializeNestedObjectToQueryParams(queryParams);
|
||||
|
||||
if (queryPart.length > 0) url = url + `?${queryPart}`;
|
||||
}
|
||||
if (mode === 'view') {
|
||||
navigate(url);
|
||||
} else {
|
||||
if (confirm('The app will be opened in a new tab as the action is triggered from the editor.')) {
|
||||
window.open(urlJoin(window.public_config?.TOOLJET_HOST, url));
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('go_to_app', 'go-to-app', error, eventObj, { eventId: event.eventId });
|
||||
return Promise.reject();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
case 'show-modal':
|
||||
return get().eventsSlice.showModal(event.modal, true);
|
||||
return get().eventsSlice.showModal(event.modal, true, eventObj);
|
||||
|
||||
case 'close-modal':
|
||||
return get().eventsSlice.showModal(event.modal, false);
|
||||
return get().eventsSlice.showModal(event.modal, false, eventObj);
|
||||
case 'copy-to-clipboard': {
|
||||
const contentToCopy = getResolvedValue(event.contentToCopy, customVariables);
|
||||
copyToClipboard(contentToCopy);
|
||||
|
|
@ -508,7 +617,7 @@ export const createEventsSlice = (set, get) => ({
|
|||
}
|
||||
|
||||
case 'set-table-page': {
|
||||
get().eventsSlice.setTablePageIndex(event.table, getResolvedValue(event.pageIndex));
|
||||
get().eventsSlice.setTablePageIndex(event.table, getResolvedValue(event.pageIndex), eventObj);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -631,85 +740,110 @@ export const createEventsSlice = (set, get) => ({
|
|||
// return;
|
||||
}
|
||||
case 'control-component': {
|
||||
// let component = Object.values(getCurrentState()?.components ?? {}).filter(
|
||||
// (component) => component.id === event.componentId
|
||||
// )[0];
|
||||
const component = getExposedValueOfComponent(event.componentId);
|
||||
const action = component?.[event.componentSpecificActionHandle];
|
||||
// let action = '';
|
||||
// let actionArguments = '';
|
||||
// check if component id not found then try to find if its available as child widget else continue
|
||||
// with normal flow finding action
|
||||
// if (component == undefined) {
|
||||
// component = _ref.appDefinition.pages[getCurrentState()?.page?.id].components[event.componentId].component;
|
||||
// const parent = Object.values(getCurrentState()?.components ?? {}).find(
|
||||
// (item) => item.id === component.parent
|
||||
// );
|
||||
// const child = Object.values(parent?.children).find((item) => item.id === event.componentId);
|
||||
// if (child) {
|
||||
// action = child[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// } else {
|
||||
// //normal component outside a container ex : form
|
||||
// action = component?.[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, undefined, customVariables),
|
||||
// }));
|
||||
// console.log('actionArguments', event.componentSpecificActionParams);
|
||||
const actionArguments = event.componentSpecificActionParams.map((param) => {
|
||||
const value = getResolvedValue(param.value, customVariables);
|
||||
return {
|
||||
...param,
|
||||
value: value,
|
||||
// value: resolveCode(re.valueWithBrackets, getAllExposedValues()),
|
||||
};
|
||||
});
|
||||
// const actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, getAllExposedValues(), customVariables),
|
||||
// }));
|
||||
try {
|
||||
// let component = Object.values(getCurrentState()?.components ?? {}).filter(
|
||||
// (component) => component.id === event.componentId
|
||||
// )[0];
|
||||
const { event } = eventObj;
|
||||
if (!event.componentSpecificActionHandle) {
|
||||
throw new Error('No component-specific action handle provided.');
|
||||
}
|
||||
const component = getExposedValueOfComponent(event.componentId);
|
||||
if (!event.componentId || !Object.keys(component).length) {
|
||||
throw new Error('No component ID provided for control-component action.');
|
||||
}
|
||||
const action = component?.[event.componentSpecificActionHandle];
|
||||
// let action = '';
|
||||
// let actionArguments = '';
|
||||
// check if component id not found then try to find if its available as child widget else continue
|
||||
// with normal flow finding action
|
||||
// if (component == undefined) {
|
||||
// component = _ref.appDefinition.pages[getCurrentState()?.page?.id].components[event.componentId].component;
|
||||
// const parent = Object.values(getCurrentState()?.components ?? {}).find(
|
||||
// (item) => item.id === component.parent
|
||||
// );
|
||||
// const child = Object.values(parent?.children).find((item) => item.id === event.componentId);
|
||||
// if (child) {
|
||||
// action = child[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// } else {
|
||||
// //normal component outside a container ex : form
|
||||
// action = component?.[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, undefined, customVariables),
|
||||
// }));
|
||||
// console.log('actionArguments', event.componentSpecificActionParams);
|
||||
const actionArguments = event.componentSpecificActionParams.map((param) => {
|
||||
const value = getResolvedValue(param.value, customVariables);
|
||||
return {
|
||||
...param,
|
||||
value: value,
|
||||
// value: resolveCode(re.valueWithBrackets, getAllExposedValues()),
|
||||
};
|
||||
});
|
||||
// const actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, getAllExposedValues(), customVariables),
|
||||
// }));
|
||||
|
||||
const actionPromise = action && action(...actionArguments.map((argument) => argument.value));
|
||||
return actionPromise ?? Promise.resolve();
|
||||
const actionPromise = action && action(...actionArguments.map((argument) => argument.value));
|
||||
return actionPromise ?? Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('control_component', 'control-component', error, eventObj, {
|
||||
eventId: event.eventId,
|
||||
});
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
case 'switch-page': {
|
||||
const { switchPage } = get();
|
||||
const page = get().modules.canvas.pages.find((page) => page.id === event.pageId);
|
||||
const queryParams = event.queryParams || [];
|
||||
if (!page.disabled) {
|
||||
const resolvedQueryParams = [];
|
||||
queryParams.forEach((param) => {
|
||||
resolvedQueryParams.push([
|
||||
getResolvedValue(param[0], customVariables),
|
||||
getResolvedValue(param[1], customVariables),
|
||||
]);
|
||||
});
|
||||
const currentUrlParams = new URLSearchParams(window.location.search);
|
||||
currentUrlParams.forEach((value, key) => {
|
||||
if (key === 'version' || key === 'env') {
|
||||
// if version or env is in current url query param but not in resolved params then add it to resolvedQueryParams
|
||||
const exists = resolvedQueryParams.some(([resolvedKey]) => resolvedKey === key);
|
||||
if (!exists) {
|
||||
resolvedQueryParams.unshift([key, value]);
|
||||
try {
|
||||
const { pageId } = event;
|
||||
if (!pageId) {
|
||||
throw new Error('No page ID provided');
|
||||
}
|
||||
const { switchPage } = get();
|
||||
const page = get().modules.canvas.pages.find((page) => page.id === event.pageId);
|
||||
const queryParams = event.queryParams || [];
|
||||
if (!page.disabled) {
|
||||
const resolvedQueryParams = [];
|
||||
queryParams.forEach((param) => {
|
||||
resolvedQueryParams.push([
|
||||
getResolvedValue(param[0], customVariables),
|
||||
getResolvedValue(param[1], customVariables),
|
||||
]);
|
||||
});
|
||||
const currentUrlParams = new URLSearchParams(window.location.search);
|
||||
currentUrlParams.forEach((value, key) => {
|
||||
if (key === 'version' || key === 'env') {
|
||||
// if version or env is in current url query param but not in resolved params then add it to resolvedQueryParams
|
||||
const exists = resolvedQueryParams.some(([resolvedKey]) => resolvedKey === key);
|
||||
if (!exists) {
|
||||
resolvedQueryParams.unshift([key, value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
switchPage(page.id, page.handle, resolvedQueryParams);
|
||||
} else {
|
||||
toast.error('Page is disabled');
|
||||
//!TODO push to debugger
|
||||
get().debugger.log({
|
||||
logLevel: 'error',
|
||||
type: 'navToDisablePage',
|
||||
kind: 'page',
|
||||
message: `Attempt to switch to disabled page ${page.name} blocked.`,
|
||||
error: 'Page is disabled',
|
||||
});
|
||||
switchPage(page.id, page.handle, resolvedQueryParams);
|
||||
} else {
|
||||
toast.error('Page is disabled');
|
||||
//!TODO push to debugger
|
||||
get().debugger.log({
|
||||
logLevel: 'error',
|
||||
type: 'navToDisablePage',
|
||||
kind: 'page',
|
||||
message: `Attempt to switch to disabled page ${page.name} blocked.`,
|
||||
error: 'Page is disabled',
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('switch_page', 'switch-page', error, eventObj, {
|
||||
eventId: event.eventId,
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,8 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
confirmed = undefined,
|
||||
mode = 'edit',
|
||||
userSuppliedParameters = {},
|
||||
component,
|
||||
eventId,
|
||||
shouldSetPreviewData = false,
|
||||
isOnLoad = false,
|
||||
moduleId = 'canvas'
|
||||
|
|
@ -247,8 +249,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
if (query) {
|
||||
dataQuery = JSON.parse(JSON.stringify(query));
|
||||
} else {
|
||||
toast.error('No query has been associated with the action.');
|
||||
return;
|
||||
throw new Error('No query selected');
|
||||
}
|
||||
|
||||
if (_.isEmpty(parameters)) {
|
||||
|
|
@ -298,6 +299,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
isLoading: true,
|
||||
data: [],
|
||||
rawData: [],
|
||||
id: queryId,
|
||||
});
|
||||
|
||||
let queryExecutionPromise = null;
|
||||
|
|
@ -367,6 +369,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
kind: query.kind,
|
||||
key: query.name,
|
||||
message: errorData?.description,
|
||||
errorTarget: 'Queries',
|
||||
error:
|
||||
query.kind === 'restapi'
|
||||
? {
|
||||
|
|
@ -435,6 +438,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
key: query.name,
|
||||
message: 'Query executed successfully',
|
||||
isQuerySuccessLog: true,
|
||||
errorTarget: 'Queries',
|
||||
});
|
||||
|
||||
setResolvedQuery(queryId, {
|
||||
|
|
@ -760,6 +764,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
error: result,
|
||||
isTransformation: true,
|
||||
isQuerySuccessLog: result?.status === 'failed' ? false : true,
|
||||
errorTarget: 'Queries',
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -340,11 +340,11 @@ const DynamicEditorBridge = (props) => {
|
|||
<div className={cx({ 'codeShow-active': codeShow }, 'wrapper-div-code-editor')}>
|
||||
<div className={cx('d-flex align-items-center justify-content-between')}>
|
||||
{paramLabel !== ' ' && !HIDDEN_CODE_HINTER_LABELS.includes(paramLabel) && (
|
||||
<div className={`field ${className}`} data-cy={`${cyLabel}-widget-parameter-label`}>
|
||||
<div className={`field text-truncate d-flex ${className}`} data-cy={`${cyLabel}-widget-parameter-label`}>
|
||||
<ToolTip
|
||||
label={t(`widget.commonProperties.${camelCase(paramLabel)}`, paramLabel)}
|
||||
meta={fieldMeta}
|
||||
labelClass={`tj-text-xsm color-slate12 ${codeShow ? 'mb-2' : 'mb-0'} ${
|
||||
labelClass={`tj-text-xsm color-slate12 w-100 text-truncate ${codeShow ? 'mb-2' : 'mb-0'} ${
|
||||
darkMode && 'color-whitish-darkmode'
|
||||
}`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/* eslint-disable react/no-string-refs */
|
||||
import React from 'react';
|
||||
import { Editor, EditorState, RichUtils, getDefaultKeyBinding, ContentState } from 'draft-js';
|
||||
import { Editor, EditorState, RichUtils, getDefaultKeyBinding, ContentState, convertFromHTML } from 'draft-js';
|
||||
import 'draft-js/dist/Draft.css';
|
||||
import { stateToHTML } from 'draft-js-export-html';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
// Custom overrides for "code" style.
|
||||
const styleMap = {
|
||||
|
|
@ -148,10 +150,16 @@ const InlineStyleControls = (props) => {
|
|||
class DraftEditor extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const blocksFromHTML = convertFromHTML(DOMPurify.sanitize(this.props.defaultValue));
|
||||
this.state = {
|
||||
editorState: EditorState.createWithContent(ContentState.createFromText(this.props.defaultValue)),
|
||||
editorState: EditorState.createWithContent(
|
||||
ContentState.createFromBlockArray(blocksFromHTML.contentBlocks, blocksFromHTML.entityMap)
|
||||
),
|
||||
};
|
||||
|
||||
this.editorContainerRef = React.createRef();
|
||||
this.controlsRef = React.createRef();
|
||||
|
||||
this.focus = () => this.refs.editor.focus();
|
||||
this.onChange = (editorState) => {
|
||||
let html = stateToHTML(editorState.getCurrentContent());
|
||||
|
|
@ -165,9 +173,63 @@ class DraftEditor extends React.Component {
|
|||
this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
//For resizing the editor container based on the height of rich text editor controls
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
if (this.controlsRef.current && this.editorContainerRef.current) {
|
||||
const controlsHeight = this.controlsRef.current.offsetHeight;
|
||||
const editorHeight = this.props.height - 46 - controlsHeight;
|
||||
this.editorContainerRef.current.style.height = `${editorHeight}px`;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.controlsRef.current) {
|
||||
this.resizeObserver.observe(this.controlsRef.current);
|
||||
}
|
||||
|
||||
const exposedVariables = {
|
||||
value: this.props.defaultValue,
|
||||
isDisabled: this.props.isDisabled,
|
||||
isVisible: this.props.isVisible,
|
||||
isLoading: this.props.isLoading,
|
||||
setValue: async (text) => {
|
||||
const blocksFromHTML = convertFromHTML(DOMPurify.sanitize(text));
|
||||
const newContentState = ContentState.createFromBlockArray(
|
||||
blocksFromHTML.contentBlocks,
|
||||
blocksFromHTML.entityMap
|
||||
);
|
||||
const newEditorState = EditorState.createWithContent(newContentState);
|
||||
const html = stateToHTML(newContentState);
|
||||
this.props.handleChange(html);
|
||||
this.setState({ editorState: newEditorState });
|
||||
},
|
||||
setDisable: async (value) => {
|
||||
this.props.setExposedVariable('isDisabled', value);
|
||||
this.props.setIsDisabled(value);
|
||||
},
|
||||
setVisibility: async (value) => {
|
||||
this.props.setExposedVariable('isVisible', value);
|
||||
this.props.setIsVisible(value);
|
||||
},
|
||||
setLoading: async (value) => {
|
||||
this.props.setExposedVariable('isLoading', value);
|
||||
this.props.setIsLoading(value);
|
||||
},
|
||||
};
|
||||
this.props.setExposedVariables(exposedVariables);
|
||||
this.props.isInitialRender.current = false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.defaultValue !== this.props.defaultValue) {
|
||||
const newContentState = ContentState.createFromText(this.props.defaultValue);
|
||||
const blocksFromHTML = convertFromHTML(DOMPurify.sanitize(this.props.defaultValue));
|
||||
const newContentState = ContentState.createFromBlockArray(blocksFromHTML.contentBlocks, blocksFromHTML.entityMap);
|
||||
const newEditorState = EditorState.createWithContent(newContentState);
|
||||
const html = stateToHTML(newContentState);
|
||||
|
||||
|
|
@ -218,13 +280,19 @@ class DraftEditor extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="RichEditor-root">
|
||||
<div className="RichEditor-controls">
|
||||
return this.props.isLoading ? (
|
||||
<div style={{ height: '100%', width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<center>
|
||||
<Loader width="16" absolute={false} />
|
||||
</center>
|
||||
</div>
|
||||
) : (
|
||||
<div className="RichEditor-root" style={{ overflowY: 'scroll', scrollbarWidth: 'none' }}>
|
||||
<div className="RichEditor-controls" ref={this.controlsRef}>
|
||||
<BlockStyleControls editorState={editorState} onToggle={this.toggleBlockType} />
|
||||
<InlineStyleControls editorState={editorState} onToggle={this.toggleInlineStyle} />
|
||||
</div>
|
||||
<div className={className} style={{ height: `${this.props.height - 60}px` }} onClick={this.focus}>
|
||||
<div className={className} ref={this.editorContainerRef} onClick={this.focus}>
|
||||
<Editor
|
||||
blockStyleFn={getBlockStyle}
|
||||
customStyleMap={styleMap}
|
||||
|
|
@ -232,7 +300,13 @@ class DraftEditor extends React.Component {
|
|||
handleKeyCommand={this.handleKeyCommand}
|
||||
keyBindingFn={this.mapKeyToEditorCommand}
|
||||
onChange={this.onChange}
|
||||
placeholder={this.props.placeholder}
|
||||
placeholder={
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: DOMPurify.sanitize(this.props.placeholder || ''),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
ref="editor"
|
||||
spellCheck={true}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ export const NumberInput = function NumberInput({
|
|||
|
||||
useEffect(() => {
|
||||
setInputValue(Number(parseFloat(properties.value).toFixed(properties.decimalPlaces)));
|
||||
if (isNaN(Number(parseFloat(properties.value).toFixed(properties.decimalPlaces)))) {
|
||||
setExposedVariable('value', null);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [properties.value]);
|
||||
|
||||
|
|
@ -144,6 +147,7 @@ export const NumberInput = function NumberInput({
|
|||
},
|
||||
clear: async function () {
|
||||
setInputValue('');
|
||||
setExposedVariable('value', null);
|
||||
fireEvent('onChange');
|
||||
},
|
||||
setLoading: async function (loading) {
|
||||
|
|
@ -167,7 +171,8 @@ export const NumberInput = function NumberInput({
|
|||
};
|
||||
if (!isNaN(value)) {
|
||||
exposedVariables.value = value;
|
||||
}
|
||||
} else exposedVariables.value = null;
|
||||
|
||||
setExposedVariables(exposedVariables);
|
||||
|
||||
isInitialRender.current = false;
|
||||
|
|
|
|||
295
frontend/src/Editor/Components/RadioButtonV2/RadioButtonV2.jsx
Normal file
295
frontend/src/Editor/Components/RadioButtonV2/RadioButtonV2.jsx
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
import React, { useEffect, useMemo, useState, useRef } from 'react';
|
||||
import Label from '@/_ui/Label';
|
||||
import cx from 'classnames';
|
||||
import './radioButtonV2.scss';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import { has, isObject } from 'lodash';
|
||||
|
||||
export const RadioButtonV2 = ({
|
||||
properties,
|
||||
styles,
|
||||
fireEvent,
|
||||
setExposedVariable,
|
||||
setExposedVariables,
|
||||
darkMode,
|
||||
componentName,
|
||||
validate,
|
||||
validation,
|
||||
}) => {
|
||||
const { label, value, options, disabledState, advanced, schema, optionsLoadingState, loadingState } = properties;
|
||||
|
||||
const {
|
||||
activeColor,
|
||||
direction,
|
||||
auto: labelAutoWidth,
|
||||
labelWidth,
|
||||
optionsTextColor,
|
||||
borderColor,
|
||||
switchOffBackgroundColor,
|
||||
handleColor,
|
||||
switchOnBackgroundColor,
|
||||
labelColor,
|
||||
alignment,
|
||||
} = styles;
|
||||
|
||||
const isInitialRender = useRef(true);
|
||||
|
||||
const [checkedValue, setCheckedValue] = useState(advanced ? findDefaultItem(schema) : value);
|
||||
const [visibility, setVisibility] = useState(properties.visibility);
|
||||
const [isLoading, setIsLoading] = useState(loadingState);
|
||||
const [isDisabled, setIsDisabled] = useState(disabledState);
|
||||
|
||||
const isMandatory = validation?.mandatory ?? false;
|
||||
const [validationStatus, setValidationStatus] = useState(validate(checkedValue));
|
||||
const { isValid, validationError } = validationStatus;
|
||||
|
||||
const labelRef = useRef();
|
||||
const radioBtnRef = useRef();
|
||||
|
||||
const selectOptions = useMemo(() => {
|
||||
let _options = advanced ? schema : options;
|
||||
if (Array.isArray(_options)) {
|
||||
let _selectOptions = _options
|
||||
.filter((data) => data?.visible ?? true)
|
||||
.map((data) => ({
|
||||
...data,
|
||||
label: data?.label,
|
||||
value: data?.value,
|
||||
isDisabled: data?.disable ?? false,
|
||||
}));
|
||||
return _selectOptions;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}, [advanced, schema, options]);
|
||||
|
||||
function findDefaultItem(optionSchema) {
|
||||
if (!Array.isArray(optionSchema)) {
|
||||
return undefined;
|
||||
}
|
||||
const foundItem = optionSchema?.find((item) => item?.default === true && item?.visible === true);
|
||||
return foundItem?.value;
|
||||
}
|
||||
|
||||
function onSelect(value) {
|
||||
const _value = isObject(value) && has(value, 'value') ? value?.value : value;
|
||||
setCheckedValue(_value);
|
||||
setExposedVariable('value', _value);
|
||||
const validationStatus = validate(_value);
|
||||
setValidationStatus(validationStatus);
|
||||
setExposedVariable('isValid', validationStatus?.isValid);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
if (advanced) {
|
||||
onSelect(findDefaultItem(schema));
|
||||
} else onSelect(value);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [advanced, JSON.stringify(schema), value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (visibility !== properties.visibility) setVisibility(properties.visibility);
|
||||
if (isLoading !== loadingState) setIsLoading(loadingState);
|
||||
if (isDisabled !== disabledState) setIsDisabled(disabledState);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [properties.visibility, loadingState, disabledState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
const _options = selectOptions?.map(({ label, value }) => ({ label, value }));
|
||||
setExposedVariable('options', _options);
|
||||
|
||||
setExposedVariable('selectOption', async function (value) {
|
||||
onSelect(value);
|
||||
fireEvent('onSelectionChange');
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify(selectOptions)]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('label', label);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [label]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
const validationStatus = validate(checkedValue);
|
||||
setValidationStatus(validationStatus);
|
||||
setExposedVariable('isValid', validationStatus?.isValid);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [validate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isMandatory', isMandatory);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isMandatory]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isLoading', loadingState);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [loadingState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isVisible', properties.visibility);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [properties.visibility]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isDisabled', disabledState);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [disabledState]);
|
||||
|
||||
useEffect(() => {
|
||||
const _options = selectOptions?.map(({ label, value }) => ({ label, value }));
|
||||
const exposedVariables = {
|
||||
value: checkedValue,
|
||||
label: label,
|
||||
options: _options,
|
||||
isValid: isValid,
|
||||
isMandatory: isMandatory,
|
||||
isLoading: loadingState,
|
||||
isVisible: properties.visibility,
|
||||
isDisabled: disabledState,
|
||||
selectOption: async function (value) {
|
||||
onSelect(value);
|
||||
fireEvent('onSelectionChange');
|
||||
},
|
||||
deselectOption: async function () {
|
||||
onSelect(null);
|
||||
fireEvent('onSelectionChange');
|
||||
},
|
||||
setVisibility: async function (value) {
|
||||
setVisibility(value);
|
||||
setExposedVariable('isVisible', value);
|
||||
},
|
||||
setDisable: async function (value) {
|
||||
setIsDisabled(value);
|
||||
setExposedVariable('isDisabled', value);
|
||||
},
|
||||
setLoading: async function (value) {
|
||||
setIsLoading(value);
|
||||
setExposedVariable('isLoading', value);
|
||||
},
|
||||
};
|
||||
setExposedVariables(exposedVariables);
|
||||
isInitialRender.current = false;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const _width = (labelWidth / 100) * 70; // Max width which label can go is 70% for better UX calculate width based on this value
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
data-cy={`label-${String(componentName).toLowerCase()} `}
|
||||
data-disabled={isDisabled}
|
||||
id={String(componentName)}
|
||||
className={cx('radio-button,', 'd-flex', {
|
||||
[alignment === 'top' &&
|
||||
((labelWidth != 0 && label?.length != 0) ||
|
||||
(labelAutoWidth && labelWidth == 0 && label && label?.length != 0))
|
||||
? 'flex-column'
|
||||
: '']: true,
|
||||
'flex-row-reverse': direction === 'right' && alignment === 'side',
|
||||
'text-right': direction === 'right' && alignment === 'top',
|
||||
invisible: !visibility,
|
||||
visibility: visibility,
|
||||
})}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
paddingLeft: '0px',
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
label={label}
|
||||
width={labelWidth}
|
||||
labelRef={labelRef}
|
||||
darkMode={darkMode}
|
||||
color={labelColor}
|
||||
defaultAlignment={alignment}
|
||||
direction={direction}
|
||||
auto={labelAutoWidth}
|
||||
isMandatory={isMandatory}
|
||||
_width={_width}
|
||||
top={alignment !== 'top' && '2px'}
|
||||
/>
|
||||
|
||||
<div className="px-0 h-100 w-100" ref={radioBtnRef}>
|
||||
{isLoading || optionsLoadingState ? (
|
||||
<Loader style={{ right: '50%', zIndex: 3, position: 'absolute' }} width="20" />
|
||||
) : (
|
||||
<div className="">
|
||||
{selectOptions.map((option, index) => {
|
||||
const isChecked = checkedValue == option.value;
|
||||
return (
|
||||
<label key={index} className="radio-button-container">
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
optionsTextColor !== '#1B1F24'
|
||||
? optionsTextColor
|
||||
: isDisabled || isLoading
|
||||
? 'var(--text-disabled)'
|
||||
: 'var(--text-primary)',
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</span>
|
||||
<input
|
||||
style={{
|
||||
marginTop: '1px',
|
||||
backgroundColor: checkedValue === option.value ? `${activeColor}` : 'white',
|
||||
}}
|
||||
checked={checkedValue == option.value}
|
||||
type="radio"
|
||||
value={option.value}
|
||||
onChange={() => {
|
||||
onSelect(option.value);
|
||||
fireEvent('onSelectionChange');
|
||||
}}
|
||||
disabled={option.isDisabled}
|
||||
/>
|
||||
<span
|
||||
className="checkmark"
|
||||
style={{
|
||||
backgroundColor:
|
||||
!isChecked && (option.isDisabled ? 'var(--surfaces-surface-03)' : switchOffBackgroundColor),
|
||||
'--selected-background-color': option.isDisabled
|
||||
? 'var(--surfaces-surface-03)'
|
||||
: switchOnBackgroundColor,
|
||||
'--selected-border-color': borderColor,
|
||||
'--selected-handle-color': option.isDisabled ? 'var(--icons-default)' : handleColor,
|
||||
border:
|
||||
!isChecked && (option.isDisabled ? 'var(--surfaces-surface-03)' : `1px solid ${borderColor}`),
|
||||
}}
|
||||
></span>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`${isValid ? '' : visibility ? 'd-flex' : 'none'}`}
|
||||
style={{
|
||||
color: 'var(--status-error-strong)',
|
||||
justifyContent: direction === 'right' ? 'flex-start' : 'flex-end',
|
||||
fontSize: '11px',
|
||||
fontWeight: '400',
|
||||
lineHeight: '16px',
|
||||
}}
|
||||
>
|
||||
{!isValid && validationError}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/* label container */
|
||||
.radio-button-container {
|
||||
position: relative;
|
||||
padding-left: 22px;
|
||||
margin-bottom: 8px;
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
// /* Hide the browser's default radio button */
|
||||
.radio-button-container input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Create a custom radio button */
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
// // /* On mouse-over, add a grey background color */
|
||||
// .radio-button-container:focus input ~ .checkmark {
|
||||
// border-color: red
|
||||
// }
|
||||
|
||||
// /* When the radio button is checked */
|
||||
.radio-button-container input:checked ~ .checkmark {
|
||||
background-color: var(--selected-background-color);
|
||||
border-color: var(--selected-border-color);
|
||||
}
|
||||
|
||||
|
||||
// /* Create the indicator (the dot/circle - hidden when not checked) */
|
||||
.checkmark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
// /* Show the indicator (dot/circle) when checked */
|
||||
.radio-button-container input:checked ~ .checkmark:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// /* Style the indicator (dot/circle) */
|
||||
.radio-button-container .checkmark:after {
|
||||
transform: translate(50%, 50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--selected-handle-color);
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useEffect } from 'react';
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import 'draft-js/dist/Draft.css';
|
||||
import { DraftEditor } from './DraftEditor';
|
||||
|
||||
|
|
@ -8,17 +9,38 @@ export const RichTextEditor = function RichTextEditor({
|
|||
properties,
|
||||
styles,
|
||||
setExposedVariable,
|
||||
setExposedVariables,
|
||||
dataCy,
|
||||
}) {
|
||||
const isInitialRender = useRef(true);
|
||||
const { visibility, disabledState, boxShadow } = styles;
|
||||
const placeholder = properties.placeholder;
|
||||
const defaultValue = properties?.defaultValue ?? '';
|
||||
|
||||
// exposing the default value at first
|
||||
const [isDisabled, setIsDisabled] = useState(disabledState);
|
||||
const [isVisible, setIsVisible] = useState(visibility);
|
||||
const [isLoading, setIsLoading] = useState(properties?.loadingState);
|
||||
|
||||
useEffect(() => {
|
||||
setExposedVariable('value', defaultValue);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
if (isDisabled !== disabledState) setIsDisabled(disabledState);
|
||||
if (isVisible !== visibility) setIsVisible(visibility);
|
||||
if (isLoading !== properties.loadingState) setIsLoading(properties.loadingState);
|
||||
}, [properties.loadingState, styles.visibility, styles.disabledState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isDisabled', disabledState);
|
||||
}, [disabledState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isVisible', visibility);
|
||||
}, [visibility]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialRender.current) return;
|
||||
setExposedVariable('isLoading', isLoading);
|
||||
}, [isLoading]);
|
||||
|
||||
function handleChange(html) {
|
||||
setExposedVariable('value', html);
|
||||
|
|
@ -26,16 +48,25 @@ export const RichTextEditor = function RichTextEditor({
|
|||
|
||||
return (
|
||||
<div
|
||||
data-disabled={disabledState}
|
||||
style={{ height: `${height}px`, display: visibility ? '' : 'none', boxShadow }}
|
||||
data-disabled={isDisabled}
|
||||
style={{ height: `${height}px`, display: isVisible ? '' : 'none', boxShadow }}
|
||||
data-cy={dataCy}
|
||||
>
|
||||
<DraftEditor
|
||||
isInitialRender={isInitialRender}
|
||||
handleChange={handleChange}
|
||||
height={height}
|
||||
width={width}
|
||||
placeholder={placeholder}
|
||||
defaultValue={defaultValue}
|
||||
isLoading={isLoading}
|
||||
isVisible={visibility}
|
||||
isDisabled={disabledState}
|
||||
setExposedVariable={setExposedVariable}
|
||||
setExposedVariables={setExposedVariables}
|
||||
setIsDisabled={setIsDisabled}
|
||||
setIsVisible={setIsVisible}
|
||||
setIsLoading={setIsLoading}
|
||||
></DraftEditor>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@ export const ToolTip = ({ label, meta, labelClass, bold = false }) => {
|
|||
|
||||
if (meta?.tip) {
|
||||
return (
|
||||
<OverlayTrigger placement="left" delay={{ show: 250, hide: 400 }} overlay={renderTooltip}>
|
||||
<label style={tooltipStyle} className={labelClass || 'form-label'}>
|
||||
<OverlayTrigger
|
||||
placement={meta?.tooltipPlacement || 'left'}
|
||||
delay={{ show: 250, hide: 400 }}
|
||||
overlay={renderTooltip}
|
||||
>
|
||||
<label style={meta?.tooltipStyle || tooltipStyle} className={labelClass || 'form-label'}>
|
||||
{label}
|
||||
</label>
|
||||
</OverlayTrigger>
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ import { useEditorActions, useEditorStore } from '@/_stores/editorStore';
|
|||
|
||||
function Logs({ logProps, idx }) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
let titleLogType = logProps?.type;
|
||||
// need to change the titleLogType to query for transformations because if transformation fails, it is eventually a query failure
|
||||
let titleLogType = logProps?.type !== 'event' ? logProps?.type : '';
|
||||
if (titleLogType === 'transformations') {
|
||||
titleLogType = 'query';
|
||||
}
|
||||
const title = ` [${capitalize(titleLogType)} ${logProps?.key}]`;
|
||||
const title = logProps?.key;
|
||||
const message =
|
||||
logProps?.type === 'navToDisablePage'
|
||||
? logProps?.message
|
||||
|
|
@ -21,19 +20,21 @@ function Logs({ logProps, idx }) {
|
|||
? 'Completed'
|
||||
: logProps?.type === 'component'
|
||||
? `Invalid property detected: ${logProps?.message}.`
|
||||
: logProps?.type === 'Custom Log'
|
||||
? logProps?.description
|
||||
: `${startCase(logProps?.type)} failed: ${
|
||||
logProps?.description ||
|
||||
logProps?.message ||
|
||||
(isString(logProps?.message) && logProps?.message) ||
|
||||
(isString(logProps?.error?.description) && logProps?.error?.description) || //added string check since description can be an object. eg: runpy
|
||||
logProps?.error?.message
|
||||
logProps?.error?.message.trim()
|
||||
}`;
|
||||
|
||||
const defaultStyles = {
|
||||
transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
|
||||
transform: open ? 'rotate(0deg)' : 'rotate(-90deg)',
|
||||
transition: '0.2s all',
|
||||
display: logProps?.isQuerySuccessLog || logProps.type === 'navToDisablePage' ? 'none' : 'inline-block',
|
||||
cursor: 'pointer',
|
||||
paddingTop: '8px',
|
||||
top: '8px',
|
||||
pointerEvents: logProps?.isQuerySuccessLog || logProps.type === 'navToDisablePage' ? 'none' : 'default',
|
||||
};
|
||||
|
||||
|
|
@ -85,20 +86,25 @@ function Logs({ logProps, idx }) {
|
|||
onClick={(e) => {
|
||||
setOpen((prev) => !prev);
|
||||
}}
|
||||
style={{ pointerEvents: logProps?.isQuerySuccessLog ? 'none' : 'default' }}
|
||||
style={{ pointerEvents: logProps?.isQuerySuccessLog ? 'none' : 'default', position: 'relative' }}
|
||||
>
|
||||
<span className={cx('position-absolute')} style={defaultStyles}>
|
||||
<SolidIcon name="cheveronright" width="16" />
|
||||
<SolidIcon name="rightarrrow" fill={`var(--icons-strong)`} width="16" />
|
||||
</span>
|
||||
<span className="w-100" style={{ paddingTop: '8px', paddingBottom: '8px', paddingLeft: '20px' }}>
|
||||
{logProps.type === 'navToDisablePage' ? (
|
||||
renderNavToDisabledPageMessage()
|
||||
) : (
|
||||
<>
|
||||
<span className="d-flex justify-content-between align-items-center text-truncate">
|
||||
<span className="text-truncate text-slate-12">{title}</span>
|
||||
<div className="d-flex align-items-center justify-content-between">
|
||||
<div className="error-target cursor-pointer">{logProps?.errorTarget}</div>
|
||||
<small className="text-slate-10 text-right ">{moment(logProps?.timestamp).fromNow()}</small>
|
||||
</span>
|
||||
</div>
|
||||
<div className={`d-flex justify-content-between align-items-center ${!open && 'text-truncate'}`}>
|
||||
<span className={` cursor-pointer debugger-error-title ${!open && 'text-truncate'}`}>
|
||||
<HighlightSecondWord text={title} />
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className={cx('mx-1', {
|
||||
'text-tomato-9': !logProps?.isQuerySuccessLog,
|
||||
|
|
@ -134,3 +140,22 @@ function Logs({ logProps, idx }) {
|
|||
let isString = (value) => typeof value === 'string' || value instanceof String;
|
||||
|
||||
export default Logs;
|
||||
|
||||
const HighlightSecondWord = ({ text }) => {
|
||||
const processedText = text.split(/(\[.*?\])/).map((segment, index) => {
|
||||
if (segment.startsWith('[') && segment.endsWith(']')) {
|
||||
const content = segment.slice(1, -1).split(' ');
|
||||
const firstWord = content[0];
|
||||
const secondWord = content[1];
|
||||
|
||||
return (
|
||||
<span key={index}>
|
||||
[{firstWord} <b>{secondWord}</b>]
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return segment;
|
||||
});
|
||||
|
||||
return <span>{processedText}</span>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,22 +15,86 @@ export const containerConfig = {
|
|||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
section: 'additionalActions',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
section: 'additionalActions',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: true,
|
||||
},
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
section: 'additionalActions',
|
||||
displayName: 'Disable',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
showHeader: {
|
||||
type: 'toggle',
|
||||
displayName: 'Show header',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
defaultChildren: [
|
||||
{
|
||||
componentName: 'Text',
|
||||
layout: {
|
||||
top: 20,
|
||||
left: 1,
|
||||
height: 40,
|
||||
},
|
||||
displayName: 'ContainerText',
|
||||
properties: ['text'],
|
||||
accessorKey: 'text',
|
||||
styles: ['fontWeight', 'textSize', 'textColor'],
|
||||
defaultValue: {
|
||||
text: 'Container title',
|
||||
fontWeight: 'bold',
|
||||
textSize: 16,
|
||||
textColor: '#000',
|
||||
},
|
||||
},
|
||||
],
|
||||
events: {},
|
||||
styles: {
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background color',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#fff',
|
||||
},
|
||||
},
|
||||
headerBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Header',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#fff',
|
||||
},
|
||||
},
|
||||
headerHeight: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Header height',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 80,
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'code',
|
||||
displayName: 'Border radius',
|
||||
|
|
@ -50,40 +114,48 @@ export const containerConfig = {
|
|||
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: {},
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
visible: { value: '{{true}}' },
|
||||
loadingState: { value: `{{false}}` },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
backgroundColor: { value: '#fff' },
|
||||
headerBackgroundColor: { value: '#fff' },
|
||||
borderRadius: { value: '4' },
|
||||
borderColor: { value: '#fff' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
headerHeight: { value: '80' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { passinputConfig } from './passwordinput';
|
|||
import { datepickerConfig } from './datepicker';
|
||||
import { checkboxConfig } from './checkbox';
|
||||
import { radiobuttonConfig } from './radiobutton';
|
||||
import { radiobuttonV2Config } from './radioButtonV2';
|
||||
import { toggleswitchConfig } from './toggleswitch';
|
||||
import { toggleSwitchV2Config } from './toggleswitchv2';
|
||||
import { textareaConfig } from './textarea';
|
||||
|
|
@ -65,7 +66,8 @@ export {
|
|||
passinputConfig,
|
||||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonConfig, //!Depreciated
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig, //!Depreciated
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ export const numberinputConfig = {
|
|||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
value: 99,
|
||||
value: 0,
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
|
|
|
|||
295
frontend/src/Editor/WidgetManager/configs/radioButtonV2.js
Normal file
295
frontend/src/Editor/WidgetManager/configs/radioButtonV2.js
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
export const radiobuttonV2Config = {
|
||||
name: 'RadioButton',
|
||||
displayName: 'Radio Button',
|
||||
description: 'Select one from multiple choices',
|
||||
component: 'RadioButtonV2',
|
||||
defaultSize: {
|
||||
width: 12,
|
||||
height: 43,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
validation: {
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Select',
|
||||
},
|
||||
accordian: 'Data',
|
||||
},
|
||||
advanced: {
|
||||
type: 'toggle',
|
||||
displayName: 'Dynamic options',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
schema: {
|
||||
type: 'code',
|
||||
displayName: 'Schema',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsLoadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Options loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter tooltip text',
|
||||
},
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onSelectionChange: { displayName: 'On select' },
|
||||
},
|
||||
styles: {
|
||||
labelColor: {
|
||||
type: 'color',
|
||||
displayName: 'Color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: 'Direction',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
labelWidth: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
switchOnBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Checked background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
tip: 'Checked background',
|
||||
tooltipStyle: {},
|
||||
tooltipPlacement: 'bottom',
|
||||
},
|
||||
switchOffBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Unchecked background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
tip: 'Unchecked background',
|
||||
tooltipStyle: {},
|
||||
tooltipPlacement: 'bottom',
|
||||
},
|
||||
handleColor: {
|
||||
type: 'color',
|
||||
displayName: 'Handle color',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
optionsTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'selectOption',
|
||||
displayName: 'Select option',
|
||||
params: [{ handle: 'option', displayName: 'Option' }],
|
||||
},
|
||||
{
|
||||
handle: 'deselectOption',
|
||||
displayName: 'Deselect option',
|
||||
params: [{ handle: 'option', displayName: 'Option' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
label: 'Select',
|
||||
},
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: { value: 'Select' },
|
||||
value: { value: '{{"2"}}' },
|
||||
advanced: { value: `{{false}}` },
|
||||
options: {
|
||||
value: [
|
||||
{
|
||||
label: 'option1',
|
||||
value: '1',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: false },
|
||||
},
|
||||
{
|
||||
label: 'option2',
|
||||
value: '2',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: true },
|
||||
},
|
||||
{
|
||||
label: 'option3',
|
||||
value: '3',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
optionsLoadingState: { value: '{{false}}' },
|
||||
optionVisibility: { value: '{{[true, true, true]}}' },
|
||||
optionDisable: { value: '{{[false, false, false]}}' },
|
||||
schema: {
|
||||
value:
|
||||
"{{[\t{label: 'option1',value: '1',disable: false,visible: true,default: true},{label: 'option2',value: '2',disable: false,visible: true},{label: 'option3',value: '3',disable: false,visible: true}\t]}}",
|
||||
},
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
labelColor: { value: '#11181C' },
|
||||
direction: { value: 'left' },
|
||||
alignment: { value: 'side' },
|
||||
auto: { value: '{{false}}' },
|
||||
labelWidth: { value: '20' },
|
||||
borderColor: { value: '#FFFFFF' },
|
||||
switchOffBackgroundColor: { value: '#FFFFFF' },
|
||||
switchOnBackgroundColor: { value: '#4368E3' },
|
||||
handleColor: { value: '#FFFFFF' },
|
||||
optionsTextColor: { value: '#11181C' },
|
||||
padding: { value: 'default' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
export const radiobuttonConfig = {
|
||||
name: 'RadioButton',
|
||||
displayName: 'Radio Button',
|
||||
name: 'RadioButtonLegacy',
|
||||
displayName: 'Radio Button (Legacy)',
|
||||
description: 'Select one from multiple choices',
|
||||
component: 'RadioButton',
|
||||
defaultSize: {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,15 @@ export const richtextareaConfig = {
|
|||
defaultValue: 'Default text',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Show loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
section: 'additionalActions',
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
|
|
@ -55,6 +64,28 @@ export const richtextareaConfig = {
|
|||
exposedVariables: {
|
||||
value: '',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set value',
|
||||
params: [{ handle: 'value', displayName: 'Value', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
|
|
@ -63,6 +94,7 @@ export const richtextareaConfig = {
|
|||
properties: {
|
||||
placeholder: { value: 'Placeholder text' },
|
||||
defaultValue: { value: '' },
|
||||
loadingState: { value: `{{false}}` },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ export const tableConfig = {
|
|||
onCellValueChanged: { displayName: 'Cell value changed' },
|
||||
onFilterChanged: { displayName: 'Filter changed' },
|
||||
onNewRowsAdded: { displayName: 'Add new rows' },
|
||||
onTableDataDownload: { displayName: 'Download data' },
|
||||
},
|
||||
styles: {
|
||||
textColor: {
|
||||
|
|
@ -310,6 +311,16 @@ export const tableConfig = {
|
|||
{ displayName: 'Wrap', value: 'wrap' },
|
||||
],
|
||||
},
|
||||
headerCasing: {
|
||||
type: 'switch',
|
||||
displayName: 'Header casing',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Data',
|
||||
options: [
|
||||
{ displayName: 'AA', value: 'uppercase' },
|
||||
{ displayName: 'As typed', value: 'none' },
|
||||
],
|
||||
},
|
||||
tableType: {
|
||||
type: 'select',
|
||||
displayName: 'Row style',
|
||||
|
|
@ -529,6 +540,7 @@ export const tableConfig = {
|
|||
value: [
|
||||
{
|
||||
name: 'id',
|
||||
key: 'id',
|
||||
id: 'e3ecbf7fa52c4d7210a93edb8f43776267a489bad52bd108be9588f790126737',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -548,6 +560,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'name',
|
||||
key: 'name',
|
||||
id: '5d2a3744a006388aadd012fcc15cc0dbcb5f9130e0fbb64c558561c97118754a',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -556,6 +569,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'email',
|
||||
key: 'email',
|
||||
id: 'afc9a5091750a1bd4760e38760de3b4be11a43452ae8ae07ce2eebc569fe9a7f',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -564,6 +578,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'date',
|
||||
key: 'date',
|
||||
id: '27b75c8af9d34d1eaa1f9bb7f8f9f7b0abf1823e799748c8bb57e74f53b2c1dc',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -576,6 +591,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'mobile_number',
|
||||
key: 'mobile_number',
|
||||
id: '9c2e3c40572a4aefb8e179ee39a0e1ac9dc2b2e6634be56e1c05be13c3d1de56',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -652,6 +668,7 @@ export const tableConfig = {
|
|||
styles: {
|
||||
textColor: { value: '#000' },
|
||||
columnHeaderWrap: { value: 'fixed' },
|
||||
headerCasing: { value: 'uppercase' },
|
||||
actionButtonRadius: { value: '0' },
|
||||
cellSize: { value: 'regular' },
|
||||
borderRadius: { value: '8' },
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export const LEGACY_ITEMS = ['ToggleSwitchLegacy', 'DropdownLegacy', 'MultiselectLegacy'];
|
||||
export const LEGACY_ITEMS = ['ToggleSwitchLegacy', 'DropdownLegacy', 'MultiselectLegacy', 'RadioButtonLegacy'];
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig,
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
@ -68,6 +69,7 @@ export const widgets = [
|
|||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig,
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
|
|||
|
|
@ -232,11 +232,24 @@
|
|||
}
|
||||
|
||||
.debugger-content {
|
||||
padding: 0px 16px;
|
||||
background-color: var(--base);
|
||||
cursor: pointer;
|
||||
|
||||
hr {
|
||||
margin-top: 0px !important;
|
||||
margin-bottom: 16px !important;
|
||||
margin: 0px !important;
|
||||
margin-top: 16px !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--slate3);
|
||||
}
|
||||
|
||||
.error-target {
|
||||
background-color: var(--interactive-overlays-fill-hover) !important;
|
||||
padding: 4px 7px;
|
||||
border-radius: 7px;
|
||||
color: var(--slate10)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14400,7 +14400,6 @@ color: var(--text-default);
|
|||
.debugger-card-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.left-sidebar-header-btn {
|
||||
|
|
@ -14743,7 +14742,6 @@ color: var(--text-default);
|
|||
.debugger-card-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.left-sidebar-header-btn {
|
||||
|
|
@ -15103,7 +15101,6 @@ color: var(--text-default);
|
|||
.debugger-card-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.left-sidebar-header-btn {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.0.5-ce
|
||||
3.1.0-ce
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"scripts": {
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "nest build",
|
||||
"postbuild": "npm run copy-schemas",
|
||||
"lint": "eslint . '**/*.ts'",
|
||||
"format": "eslint . --fix '**/*.ts'",
|
||||
"start": "nest start",
|
||||
|
|
@ -32,7 +33,8 @@
|
|||
"db:setup": "npm run db:create && npm run db:migrate",
|
||||
"db:setup:prod": "npm run db:create:prod && npm run db:migrate:prod",
|
||||
"db:reset": "npm run db:drop && npm run db:setup",
|
||||
"typeorm": "typeorm-ts-node-commonjs"
|
||||
"typeorm": "typeorm-ts-node-commonjs",
|
||||
"copy-schemas": "copyfiles -u 4 src/dto/validators/schemas/**/*.json dist/src/dto/validators/schemas"
|
||||
},
|
||||
"dependencies": {
|
||||
"@casl/ability": "^5.3.1",
|
||||
|
|
@ -60,6 +62,7 @@
|
|||
"class-validator": "^0.14.0",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"copyfiles": "^2.4.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"express-http-proxy": "^1.6.3",
|
||||
"fast-csv": "^4.3.6",
|
||||
|
|
@ -76,8 +79,8 @@
|
|||
"lodash": "^4.17.21",
|
||||
"module-from-string": "^3.3.0",
|
||||
"nestjs-pino": "^1.4.0",
|
||||
"node-sql-parser": "^5.3.1",
|
||||
"node-mailer": "^0.1.1",
|
||||
"node-sql-parser": "^5.3.1",
|
||||
"nodemailer": "^6.6.3",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.0",
|
||||
|
|
@ -152,4 +155,4 @@
|
|||
"node": "18.18.2",
|
||||
"npm": "9.8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -433,4 +433,4 @@ export const getSubpath = () => {
|
|||
}
|
||||
}
|
||||
return subpath;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,33 @@ export const containerConfig = {
|
|||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
section: 'additionalActions',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
showHeader: {
|
||||
type: 'toggle',
|
||||
displayName: 'Show header',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
|
|
@ -25,12 +52,29 @@ export const containerConfig = {
|
|||
styles: {
|
||||
backgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Background color',
|
||||
displayName: 'Background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#fff',
|
||||
},
|
||||
},
|
||||
headerBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Header',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: '#fff',
|
||||
},
|
||||
},
|
||||
headerHeight: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Header height',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 80,
|
||||
},
|
||||
accordian: 'field',
|
||||
},
|
||||
borderRadius: {
|
||||
type: 'code',
|
||||
displayName: 'Border radius',
|
||||
|
|
@ -50,40 +94,67 @@ export const containerConfig = {
|
|||
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: {},
|
||||
|
||||
defaultChildren: [
|
||||
{
|
||||
componentName: 'Text',
|
||||
layout: {
|
||||
top: 20,
|
||||
left: 1,
|
||||
height: 40,
|
||||
},
|
||||
displayName: 'ContainerText',
|
||||
properties: ['text'],
|
||||
accessorKey: 'text',
|
||||
styles: ['fontWeight', 'textSize', 'textColor'],
|
||||
defaultValue: {
|
||||
text: 'Container title',
|
||||
fontWeight: 'bold',
|
||||
textSize: 16,
|
||||
textColor: '#000',
|
||||
},
|
||||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
isLoading: false,
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
visible: { value: '{{true}}' },
|
||||
loadingState: { value: `{{false}}` },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
backgroundColor: { value: '#fff' },
|
||||
headerBackgroundColor: { value: '#fff' },
|
||||
borderRadius: { value: '4' },
|
||||
borderColor: { value: '#fff' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
headerHeight: { value: `80`, },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { passinputConfig } from './passwordinput';
|
|||
import { datepickerConfig } from './datepicker';
|
||||
import { checkboxConfig } from './checkbox';
|
||||
import { radiobuttonConfig } from './radiobutton';
|
||||
import { radiobuttonV2Config } from './radioButtonV2';
|
||||
import { toggleswitchConfig } from './toggleswitch';
|
||||
import { toggleSwitchV2Config } from './toggleswitchv2';
|
||||
import { textareaConfig } from './textarea';
|
||||
|
|
@ -65,7 +66,8 @@ const widgets = {
|
|||
passinputConfig,
|
||||
datepickerConfig,
|
||||
checkboxConfig,
|
||||
radiobuttonConfig,
|
||||
radiobuttonConfig, //!Depreciated
|
||||
radiobuttonV2Config,
|
||||
toggleswitchConfig, //!Depreciated
|
||||
toggleSwitchV2Config,
|
||||
textareaConfig,
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ export const numberinputConfig = {
|
|||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
value: 99,
|
||||
value: 0,
|
||||
isMandatory: false,
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
|
|
|
|||
295
server/src/helpers/widget-config/radioButtonV2.js
Normal file
295
server/src/helpers/widget-config/radioButtonV2.js
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
export const radiobuttonV2Config = {
|
||||
name: 'RadioButton',
|
||||
displayName: 'Radio Button',
|
||||
description: 'Select one from multiple choices',
|
||||
component: 'RadioButtonV2',
|
||||
defaultSize: {
|
||||
width: 12,
|
||||
height: 43,
|
||||
},
|
||||
others: {
|
||||
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
|
||||
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
|
||||
},
|
||||
validation: {
|
||||
customRule: {
|
||||
type: 'code',
|
||||
displayName: 'Custom validation',
|
||||
placeholder: `{{components.text2.text=='yes'&&'valid'}}`,
|
||||
},
|
||||
mandatory: { type: 'toggle', displayName: 'Make this field mandatory' },
|
||||
},
|
||||
properties: {
|
||||
label: {
|
||||
type: 'code',
|
||||
displayName: 'Label',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Select',
|
||||
},
|
||||
accordian: 'Data',
|
||||
},
|
||||
advanced: {
|
||||
type: 'toggle',
|
||||
displayName: 'Dynamic options',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
schema: {
|
||||
type: 'code',
|
||||
displayName: 'Schema',
|
||||
conditionallyRender: {
|
||||
key: 'advanced',
|
||||
value: true,
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
optionsLoadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Options loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
accordian: 'Options',
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Loading state',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
displayName: 'Visibility',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
|
||||
section: 'additionalActions',
|
||||
},
|
||||
disabledState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Disable',
|
||||
validation: { schema: { type: 'boolean' }, defaultValue: true },
|
||||
section: 'additionalActions',
|
||||
},
|
||||
tooltip: {
|
||||
type: 'code',
|
||||
displayName: 'Tooltip',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'Enter tooltip text',
|
||||
},
|
||||
section: 'additionalActions',
|
||||
placeholder: 'Enter tooltip text',
|
||||
},
|
||||
},
|
||||
events: {
|
||||
onSelectionChange: { displayName: 'On select' },
|
||||
},
|
||||
styles: {
|
||||
labelColor: {
|
||||
type: 'color',
|
||||
displayName: 'Color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
|
||||
accordian: 'label',
|
||||
},
|
||||
alignment: {
|
||||
type: 'switch',
|
||||
displayName: 'Alignment',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'side' },
|
||||
options: [
|
||||
{ displayName: 'Side', value: 'side' },
|
||||
{ displayName: 'Top', value: 'top' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
direction: {
|
||||
type: 'switch',
|
||||
displayName: 'Direction',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'left' },
|
||||
showLabel: false,
|
||||
isIcon: true,
|
||||
options: [
|
||||
{ displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' },
|
||||
{ displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' },
|
||||
],
|
||||
accordian: 'label',
|
||||
},
|
||||
labelWidth: {
|
||||
type: 'slider',
|
||||
displayName: 'Width',
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
auto: {
|
||||
type: 'checkbox',
|
||||
displayName: 'auto',
|
||||
showLabel: false,
|
||||
validation: { schema: { type: 'boolean' } },
|
||||
accordian: 'label',
|
||||
conditionallyRender: {
|
||||
key: 'alignment',
|
||||
value: 'side',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
},
|
||||
borderColor: {
|
||||
type: 'color',
|
||||
displayName: 'Border',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
switchOnBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Checked background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
tip: 'Checked background',
|
||||
tooltipStyle: {},
|
||||
tooltipPlacement: 'bottom',
|
||||
},
|
||||
switchOffBackgroundColor: {
|
||||
type: 'color',
|
||||
displayName: 'Unchecked background',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
tip: 'Unchecked background',
|
||||
tooltipStyle: {},
|
||||
tooltipPlacement: 'bottom',
|
||||
},
|
||||
handleColor: {
|
||||
type: 'color',
|
||||
displayName: 'Handle color',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
optionsTextColor: {
|
||||
type: 'color',
|
||||
displayName: 'Text',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
accordian: 'switch',
|
||||
},
|
||||
padding: {
|
||||
type: 'switch',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 'default',
|
||||
},
|
||||
isFxNotRequired: true,
|
||||
options: [
|
||||
{ displayName: 'Default', value: 'default' },
|
||||
{ displayName: 'None', value: 'none' },
|
||||
],
|
||||
accordian: 'container',
|
||||
},
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'selectOption',
|
||||
displayName: 'Select option',
|
||||
params: [{ handle: 'option', displayName: 'Option' }],
|
||||
},
|
||||
{
|
||||
handle: 'deselectOption',
|
||||
displayName: 'Deselect option',
|
||||
params: [{ handle: 'option', displayName: 'Option' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
exposedVariables: {
|
||||
label: 'Select',
|
||||
},
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
showOnMobile: { value: '{{false}}' },
|
||||
},
|
||||
validation: {
|
||||
mandatory: { value: '{{false}}' },
|
||||
},
|
||||
properties: {
|
||||
label: { value: 'Select' },
|
||||
value: { value: '{{"2"}}' },
|
||||
advanced: { value: `{{false}}` },
|
||||
options: {
|
||||
value: [
|
||||
{
|
||||
label: 'option1',
|
||||
value: '1',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: false },
|
||||
},
|
||||
{
|
||||
label: 'option2',
|
||||
value: '2',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: true },
|
||||
},
|
||||
{
|
||||
label: 'option3',
|
||||
value: '3',
|
||||
disable: { value: false },
|
||||
visible: { value: true },
|
||||
default: { value: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
loadingState: { value: '{{false}}' },
|
||||
optionsLoadingState: { value: '{{false}}' },
|
||||
optionVisibility: { value: '{{[true, true, true]}}' },
|
||||
optionDisable: { value: '{{[false, false, false]}}' },
|
||||
schema: {
|
||||
value:
|
||||
"{{[\t{label: 'option1',value: '1',disable: false,visible: true,default: true},{label: 'option2',value: '2',disable: false,visible: true},{label: 'option3',value: '3',disable: false,visible: true}\t]}}",
|
||||
},
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
labelColor: { value: '#11181C' },
|
||||
direction: { value: 'left' },
|
||||
alignment: { value: 'side' },
|
||||
auto: { value: '{{false}}' },
|
||||
labelWidth: { value: '20' },
|
||||
borderColor: { value: '#FFFFFF' },
|
||||
switchOffBackgroundColor: { value: '#FFFFFF' },
|
||||
switchOnBackgroundColor: { value: '#4368E3' },
|
||||
handleColor: { value: '#FFFFFF' },
|
||||
optionsTextColor: { value: '#11181C' },
|
||||
padding: { value: 'default' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -28,6 +28,15 @@ export const richtextareaConfig = {
|
|||
defaultValue: 'Default text',
|
||||
},
|
||||
},
|
||||
loadingState: {
|
||||
type: 'toggle',
|
||||
displayName: 'Show loading state',
|
||||
validation: {
|
||||
schema: { type: 'boolean' },
|
||||
defaultValue: false,
|
||||
},
|
||||
section: 'additionalActions',
|
||||
},
|
||||
},
|
||||
events: {},
|
||||
styles: {
|
||||
|
|
@ -55,6 +64,28 @@ export const richtextareaConfig = {
|
|||
exposedVariables: {
|
||||
value: '',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
handle: 'setValue',
|
||||
displayName: 'Set value',
|
||||
params: [{ handle: 'value', displayName: 'Value', defaultValue: 'New text' }],
|
||||
},
|
||||
{
|
||||
handle: 'setDisable',
|
||||
displayName: 'Set disable',
|
||||
params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setVisibility',
|
||||
displayName: 'Set visibility',
|
||||
params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }],
|
||||
},
|
||||
{
|
||||
handle: 'setLoading',
|
||||
displayName: 'Set loading',
|
||||
params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }],
|
||||
},
|
||||
],
|
||||
definition: {
|
||||
others: {
|
||||
showOnDesktop: { value: '{{true}}' },
|
||||
|
|
@ -63,6 +94,7 @@ export const richtextareaConfig = {
|
|||
properties: {
|
||||
placeholder: { value: 'Placeholder text' },
|
||||
defaultValue: { value: '' },
|
||||
loadingState: { value: `{{false}}` },
|
||||
},
|
||||
events: [],
|
||||
styles: {
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ export const tableConfig = {
|
|||
onCellValueChanged: { displayName: 'Cell value changed' },
|
||||
onFilterChanged: { displayName: 'Filter changed' },
|
||||
onNewRowsAdded: { displayName: 'Add new rows' },
|
||||
onTableDataDownload: { displayName: 'Download data' },
|
||||
},
|
||||
styles: {
|
||||
textColor: {
|
||||
|
|
@ -310,6 +311,16 @@ export const tableConfig = {
|
|||
{ displayName: 'Wrap', value: 'wrap' },
|
||||
],
|
||||
},
|
||||
headerCasing: {
|
||||
type: 'switch',
|
||||
displayName: 'Header casing',
|
||||
validation: { schema: { type: 'string' } },
|
||||
accordian: 'Data',
|
||||
options: [
|
||||
{ displayName: 'AA', value: 'uppercase' },
|
||||
{ displayName: 'As typed', value: 'none' },
|
||||
],
|
||||
},
|
||||
tableType: {
|
||||
type: 'select',
|
||||
displayName: 'Row style',
|
||||
|
|
@ -530,6 +541,7 @@ export const tableConfig = {
|
|||
value: [
|
||||
{
|
||||
name: 'id',
|
||||
key: 'id',
|
||||
id: 'e3ecbf7fa52c4d7210a93edb8f43776267a489bad52bd108be9588f790126737',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -549,6 +561,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'name',
|
||||
key: 'name',
|
||||
id: '5d2a3744a006388aadd012fcc15cc0dbcb5f9130e0fbb64c558561c97118754a',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -557,6 +570,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'email',
|
||||
key: 'email',
|
||||
id: 'afc9a5091750a1bd4760e38760de3b4be11a43452ae8ae07ce2eebc569fe9a7f',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -565,6 +579,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'date',
|
||||
key: 'date',
|
||||
id: '27b75c8af9d34d1eaa1f9bb7f8f9f7b0abf1823e799748c8bb57e74f53b2c1dc',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -577,6 +592,7 @@ export const tableConfig = {
|
|||
},
|
||||
{
|
||||
name: 'phone',
|
||||
key: 'phone',
|
||||
id: '9c2e3c40572a4aefb8e179ee39a0e1ac9dc2b2e6634be56e1c05be13c3d1de56',
|
||||
autogenerated: true,
|
||||
fxActiveFields: [],
|
||||
|
|
@ -653,6 +669,7 @@ export const tableConfig = {
|
|||
styles: {
|
||||
textColor: { value: '#000' },
|
||||
columnHeaderWrap: { value: 'fixed' },
|
||||
headerCasing: { value: 'uppercase' },
|
||||
actionButtonRadius: { value: '0' },
|
||||
cellSize: { value: 'regular' },
|
||||
borderRadius: { value: '8' },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
|
|
|
|||
Loading…
Reference in a new issue