diff --git a/frontend/assets/images/icons/widgets/horizontalDivider.jsx b/frontend/assets/images/icons/widgets/horizontalDivider.jsx new file mode 100644 index 0000000000..6f843ae57a --- /dev/null +++ b/frontend/assets/images/icons/widgets/horizontalDivider.jsx @@ -0,0 +1,22 @@ +import React from 'react'; + +const HorizontalDivider = ({ fill = '#D7DBDF', width = 24, className = '', viewBox = '0 0 49 48' }) => ( + + + + + + + + + + + +); + +export default HorizontalDivider; diff --git a/frontend/assets/images/icons/widgets/index.jsx b/frontend/assets/images/icons/widgets/index.jsx index 5f1715689c..82ec948164 100644 --- a/frontend/assets/images/icons/widgets/index.jsx +++ b/frontend/assets/images/icons/widgets/index.jsx @@ -13,8 +13,6 @@ import Customcomponent from './customcomponent.jsx'; import Datepicker from './datepicker.jsx'; import DateTimePickerV2 from './datetimepickerV2.jsx'; import Daterangepicker from './daterangepicker.jsx'; -import Divider from './divider.jsx'; -import DividerHorizondal from './dividerhorizontal.jsx'; import Downstatistics from './downstatistics.jsx'; import Dropdown from './dropdown.jsx'; import Filepicker from './filepicker.jsx'; @@ -59,6 +57,7 @@ import Upstatistics from './upstatistics.jsx'; import Verticaldivider from './verticaldivider.jsx'; import TimePicker from './timepicker.jsx'; import DatepickerV2 from './datepickerv2.jsx'; +import HorizontalDivider from './horizontalDivider.jsx'; import PhoneInput from './phoneinput.jsx'; import EmailInput from './emailinput.jsx'; @@ -108,9 +107,7 @@ const WidgetIcon = (props) => { case 'daterangepicker': return ; case 'horizontaldivider': - return ; - case 'divider-horizondal': - return ; + return ; case 'downstatistics': return ; case 'dropdown': diff --git a/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx b/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx index 7862db5676..f6d6419ac4 100644 --- a/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx +++ b/frontend/src/AppBuilder/AppCanvas/RenderWidget.jsx @@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'; import ErrorBoundary from '@/_ui/ErrorBoundary'; import { BOX_PADDING } from './appCanvasConstants'; -const shouldAddBoxShadowAndVisibility = [ +const SHOULD_ADD_BOX_SHADOW_AND_VISIBILITY = [ 'Table', 'TextInput', 'TextArea', @@ -30,6 +30,8 @@ const shouldAddBoxShadowAndVisibility = [ 'DaterangePicker', 'DatePickerV2', 'TimePicker', + 'Divider', + 'VerticalDivider', 'Link', ]; @@ -147,23 +149,22 @@ const RenderWidget = ({ placement={inCanvas ? 'auto' : 'top'} delay={{ show: 500, hide: 0 }} trigger={ - inCanvas && shouldAddBoxShadowAndVisibility.includes(component?.component) + inCanvas && SHOULD_ADD_BOX_SHADOW_AND_VISIBILITY.includes(component?.component) ? !resolvedProperties?.tooltip?.toString().trim() ? null : ['hover', 'focus'] : !resolvedGeneralProperties?.tooltip?.toString().trim() - ? null - : ['hover', 'focus'] + ? null + : ['hover', 'focus'] } overlay={(props) => renderTooltip({ props, text: inCanvas - ? `${ - shouldAddBoxShadowAndVisibility.includes(component?.component) - ? resolvedProperties?.tooltip - : resolvedGeneralProperties?.tooltip - }` + ? `${SHOULD_ADD_BOX_SHADOW_AND_VISIBILITY.includes(component?.component) + ? resolvedProperties?.tooltip + : resolvedGeneralProperties?.tooltip + }` : `${t(`widget.${component?.name}.description`, component?.description)}`, }) } diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx index c7104edb40..346d0bfc17 100644 --- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx +++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx @@ -27,6 +27,8 @@ const SHOW_ADDITIONAL_ACTIONS = [ 'Button', 'RichTextEditor', 'Image', + 'Divider', + 'VerticalDivider', 'ModalV2', 'Link', ]; @@ -41,6 +43,8 @@ const PROPERTIES_VS_ACCORDION_TITLE = { Button: 'Data', Image: 'Data', Container: 'Data', + Divider: 'Data', + VerticalDivider: 'Data', ModalV2: 'Data', Link: 'Data', }; @@ -140,6 +144,8 @@ export const baseComponentProperties = ( 'DropdownV2', 'MultiselectV2', 'Image', + 'Divider', + 'VerticalDivider', 'Link', ], Layout: [], @@ -280,7 +286,6 @@ export const baseComponentProperties = ( ), }); - return items.filter( (item) => !(item.title in accordionFilters && accordionFilters[item.title].includes(componentMeta.component)) ); diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Inspector.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Inspector.jsx index 9e227b1e05..e101069fdb 100644 --- a/frontend/src/AppBuilder/RightSideBar/Inspector/Inspector.jsx +++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Inspector.jsx @@ -86,6 +86,8 @@ const NEW_REVAMPED_COMPONENTS = [ 'Icon', 'Image', 'Container', + 'Divider', + 'VerticalDivider', 'ModalV2', 'Link', ]; diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/divider.js b/frontend/src/AppBuilder/WidgetManager/widgets/divider.js index 3905c7583d..33b64d9f56 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/divider.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/divider.js @@ -1,6 +1,6 @@ export const dividerConfig = { - name: 'Divider', - displayName: 'Divider', + name: 'HorizontalDivider', + displayName: 'Horizontal divider', description: 'Separator between components', component: 'Divider', defaultSize: { @@ -11,15 +11,12 @@ export const dividerConfig = { showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' }, showOnMobile: { type: 'toggle', displayName: 'Show on mobile' }, }, - properties: {}, - events: {}, - styles: { - dividerColor: { - type: 'colorSwatches', - displayName: 'Divider color', + properties: { + label: { + type: 'code', + displayName: 'Label', validation: { schema: { type: 'string' }, - defaultValue: '#000000', }, }, visibility: { @@ -29,6 +26,109 @@ export const dividerConfig = { schema: { type: 'boolean' }, defaultValue: true, }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, + events: {}, + styles: { + dividerColor: { + type: 'colorSwatches', + displayName: 'Divider color', + validation: { + schema: { type: 'string' }, + }, + }, + visibility: { + type: 'toggle', + displayName: 'Visibility', + validation: { + schema: { type: 'boolean' }, + defaultValue: true, + }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, + events: {}, + styles: { + dividerColor: { + type: 'color', + displayName: 'Divider color', + validation: { + schema: { type: 'string' }, + defaultValue: '#000000', + }, + accordian: 'Divider', + }, + dividerStyle: { + type: 'switch', + displayName: 'Style', + validation: { + schema: { type: 'string' }, + }, + options: [ + { displayName: 'Solid', value: 'solid' }, + { displayName: 'Dashed', value: 'dashed' }, + ], + accordian: 'Divider', + }, + labelAlignment: { + type: 'switch', + displayName: 'Label alignment', + validation: { schema: { type: 'string' }, defaultValue: 'left' }, + showLabel: true, + isIcon: true, + options: [ + { displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' }, + { displayName: 'alignhorizontalcenter', value: 'center', iconName: 'alignhorizontalcenter' }, + { displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' }, + ], + accordian: 'Divider', + isFxNotRequired: true, + }, + labelColor: { + type: 'color', + displayName: 'Label Color', + validation: { + schema: { type: 'string' }, + }, + accordian: 'Divider', + }, + boxShadow: { + type: 'boxShadow', + displayName: 'Box Shadow', + validation: { + schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, + defaultValue: '0px 0px 0px 0px #00000040', + }, + accordian: 'Divider', + }, + 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', }, }, exposedVariables: { @@ -39,11 +139,19 @@ export const dividerConfig = { showOnDesktop: { value: '{{true}}' }, showOnMobile: { value: '{{false}}' }, }, - properties: {}, + properties: { + label: { value: '' }, + visibility: { value: '{{true}}' }, + tooltip: { value: '' }, + }, events: [], styles: { - visibility: { value: '{{true}}' }, - dividerColor: { value: '#000000' }, + dividerColor: { value: '#CCD1D5' }, + labelAlignment: { value: 'center' }, + dividerStyle: { value: 'solid' }, + labelColor: { value: '#6A727C' }, + padding: { value: 'default' }, + boxShadow: { value: '0px 0px 0px 0px #00000040' }, }, }, }; diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js b/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js index e43b81adf7..df426c7b5f 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js @@ -1,17 +1,34 @@ export const verticalDividerConfig = { name: 'VerticalDivider', - displayName: 'Vertical Divider', + displayName: 'Vertical divider', description: 'Vertical line separator', component: 'VerticalDivider', defaultSize: { - width: 2, + width: 1, height: 100, }, others: { showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' }, showOnMobile: { type: 'toggle', displayName: 'Show on mobile' }, }, - properties: {}, + properties: { + visibility: { + type: 'toggle', + displayName: 'Visibility', + validation: { + schema: { type: 'boolean' }, + defaultValue: true, + }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, events: {}, styles: { dividerColor: { @@ -21,14 +38,42 @@ export const verticalDividerConfig = { schema: { type: 'string' }, defaultValue: '#000000', }, + accordian: 'Divider', }, - visibility: { - type: 'toggle', - displayName: 'Visibility', + dividerStyle: { + type: 'switch', + displayName: 'Style', validation: { - schema: { type: 'boolean' }, - defaultValue: true, + schema: { type: 'string' }, }, + options: [ + { displayName: 'Solid', value: 'solid' }, + { displayName: 'Dashed', value: 'dashed' }, + ], + accordian: 'Divider', + }, + boxShadow: { + type: 'boxShadow', + displayName: 'Box Shadow', + validation: { + schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, + defaultValue: '0px 0px 0px 0px #00000040', + }, + accordian: 'Divider', + }, + 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', }, }, exposedVariables: { @@ -39,11 +84,16 @@ export const verticalDividerConfig = { showOnDesktop: { value: '{{true}}' }, showOnMobile: { value: '{{false}}' }, }, - properties: {}, + properties: { + visibility: { value: '{{true}}' }, + tooltip: { value: '' }, + }, events: [], styles: { - visibility: { value: '{{true}}' }, - dividerColor: { value: '#000000' }, + dividerColor: { value: '#CCD1D5' }, + dividerStyle: { value: 'solid' }, + padding: { value: 'default' }, + boxShadow: { value: '0px 0px 0px 0px #00000040' }, }, }, }; diff --git a/frontend/src/AppBuilder/_helpers/editorHelpers.js b/frontend/src/AppBuilder/_helpers/editorHelpers.js index 545cc408a3..183c5c1cec 100644 --- a/frontend/src/AppBuilder/_helpers/editorHelpers.js +++ b/frontend/src/AppBuilder/_helpers/editorHelpers.js @@ -50,7 +50,7 @@ import { SvgImage } from '@/Editor/Components/SvgImage'; import { Html } from '@/Editor/Components/Html'; import { ButtonGroup } from '@/Editor/Components/ButtonGroup'; import { CustomComponent } from '@/Editor/Components/CustomComponent/CustomComponent'; -import { VerticalDivider } from '@/Editor/Components/verticalDivider'; +import { VerticalDivider } from '@/Editor/Components/VerticalDivider'; import { ColorPicker } from '@/Editor/Components/ColorPicker'; import { KanbanBoard } from '@/Editor/Components/KanbanBoard/KanbanBoard'; // import { Kanban } from '@/Editor/Components/Kanban/Kanban'; diff --git a/frontend/src/Editor/Components/Divider.jsx b/frontend/src/Editor/Components/Divider.jsx index 5935181bf7..349c6f0ddc 100644 --- a/frontend/src/Editor/Components/Divider.jsx +++ b/frontend/src/Editor/Components/Divider.jsx @@ -1,20 +1,99 @@ import React from 'react'; -export const Divider = function Divider({ styles, dataCy, height, width, darkMode }) { - const { visibility, dividerColor, boxShadow } = styles; +const DASH_WIDTH = 4; +const DASH_GAP = 4; +export const Divider = function Divider({ dataCy, height, width, darkMode, styles, properties }) { + const { labelAlignment, labelColor, dividerColor, boxShadow, dividerStyle, padding } = styles; + const { label, visibility } = properties; const color = dividerColor === '' || ['#000', '#000000'].includes(dividerColor) ? (darkMode ? '#fff' : '#000') : dividerColor; + + const dividerLineStyle = { + width: '100%', + padding: '0rem', + boxShadow, + ...(dividerStyle === 'dashed' + ? { + backgroundImage: `linear-gradient(to right, ${color} ${DASH_WIDTH}px, transparent ${DASH_GAP}px)`, + backgroundSize: `${DASH_WIDTH + DASH_GAP}px 1px`, + backgroundRepeat: 'repeat-x', + backgroundColor: 'transparent', + borderTop: 'none', + height: '1px', + } + : { + height: '1px', + backgroundColor: color, + borderTop: 'none', + }), + }; + + const labelStyles = { + color: labelColor, + boxShadow, + fontSize: '11px', + fontWeight: '500', + lineHeight: '16px', + }; + + // If no label, render the original divider + if (!label) { + return ( +
+
+
+ ); + } + + // With label - handle different positions return (
-
+ {labelAlignment === 'left' && ( + <> + {label} +
+ + )} + + {labelAlignment === 'center' && ( +
+
+ {label} +
+
+ )} + + {labelAlignment === 'right' && ( + <> +
+ {label} + + )}
); }; diff --git a/frontend/src/Editor/Components/VerticalDivider.jsx b/frontend/src/Editor/Components/VerticalDivider.jsx new file mode 100644 index 0000000000..76042c8908 --- /dev/null +++ b/frontend/src/Editor/Components/VerticalDivider.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +const DASH_WIDTH = 4; +const DASH_GAP = 4; + +export const VerticalDivider = function Divider({ styles, height, width, dataCy, darkMode, properties }) { + const { dividerColor, boxShadow, dividerStyle } = styles; + const color = + dividerColor === '' || ['#000', '#000000'].includes(dividerColor) ? (darkMode ? '#fff' : '#000') : dividerColor; + + return ( +
+
+
+ ); +}; diff --git a/frontend/src/Editor/Components/verticalDivider.jsx b/frontend/src/Editor/Components/verticalDivider.jsx deleted file mode 100644 index ba6a38748c..0000000000 --- a/frontend/src/Editor/Components/verticalDivider.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -export const VerticalDivider = function Divider({ styles, height, width, dataCy, darkMode }) { - const { visibility, dividerColor, boxShadow } = styles; - const color = - dividerColor === '' || ['#000', '#000000'].includes(dividerColor) ? (darkMode ? '#fff' : '#000') : dividerColor; - - return ( -
-
-
-
- ); -}; diff --git a/frontend/src/Editor/WidgetManager/configs/divider.js b/frontend/src/Editor/WidgetManager/configs/divider.js index 27ce6edf8e..82bb38da6f 100644 --- a/frontend/src/Editor/WidgetManager/configs/divider.js +++ b/frontend/src/Editor/WidgetManager/configs/divider.js @@ -1,5 +1,5 @@ export const dividerConfig = { - name: 'horizontalDivider', + name: 'HorizontalDivider', displayName: 'Horizontal Divider', description: 'Separator between components', component: 'Divider', @@ -11,15 +11,12 @@ export const dividerConfig = { showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' }, showOnMobile: { type: 'toggle', displayName: 'Show on mobile' }, }, - properties: {}, - events: {}, - styles: { - dividerColor: { - type: 'color', - displayName: 'Divider color', + properties: { + label: { + type: 'code', + displayName: 'Label', validation: { schema: { type: 'string' }, - defaultValue: '#000000', }, }, visibility: { @@ -29,6 +26,83 @@ export const dividerConfig = { schema: { type: 'boolean' }, defaultValue: true, }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, + events: {}, + styles: { + dividerColor: { + type: 'color', + displayName: 'Divider color', + validation: { + schema: { type: 'string' }, + defaultValue: '#000000', + }, + accordian: 'Divider', + }, + dividerStyle: { + type: 'switch', + displayName: 'Style', + validation: { + schema: { type: 'string' }, + }, + options: [ + { displayName: 'Solid', value: 'solid' }, + { displayName: 'Dashed', value: 'dashed' }, + ], + accordian: 'Divider', + }, + labelAlignment: { + type: 'switch', + displayName: 'Label alignment', + validation: { schema: { type: 'string' }, defaultValue: 'left' }, + showLabel: true, + isIcon: true, + options: [ + { displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' }, + { displayName: 'alignhorizontalcenter', value: 'center', iconName: 'alignhorizontalcenter' }, + { displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' }, + ], + accordian: 'Divider', + isFxNotRequired: true, + }, + labelColor: { + type: 'color', + displayName: 'Label Color', + validation: { + schema: { type: 'string' }, + }, + accordian: 'Divider', + }, + boxShadow: { + type: 'boxShadow', + displayName: 'Box Shadow', + validation: { + schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, + defaultValue: '0px 0px 0px 0px #00000040', + }, + accordian: 'Divider', + }, + 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', }, }, exposedVariables: { @@ -39,11 +113,19 @@ export const dividerConfig = { showOnDesktop: { value: '{{true}}' }, showOnMobile: { value: '{{false}}' }, }, - properties: {}, + properties: { + label: { value: '' }, + visibility: { value: '{{true}}' }, + tooltip: { value: '' }, + }, events: [], styles: { - visibility: { value: '{{true}}' }, - dividerColor: { value: '#000000' }, + dividerColor: { value: '#CCD1D5' }, + labelAlignment: { value: 'center' }, + dividerStyle: { value: 'solid' }, + labelColor: { value: '#6A727C' }, + padding: { value: 'default' }, + boxShadow: { value: '0px 0px 0px 0px #00000040' }, }, }, }; diff --git a/frontend/src/Editor/WidgetManager/configs/verticalDivider.js b/frontend/src/Editor/WidgetManager/configs/verticalDivider.js index 443526c3b8..34d9029e3a 100644 --- a/frontend/src/Editor/WidgetManager/configs/verticalDivider.js +++ b/frontend/src/Editor/WidgetManager/configs/verticalDivider.js @@ -1,17 +1,34 @@ export const verticalDividerConfig = { name: 'VerticalDivider', - displayName: 'Vertical Divider', + displayName: 'Vertical divider', description: 'Vertical line separator', component: 'VerticalDivider', defaultSize: { - width: 2, + width: 1, height: 100, }, others: { showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' }, showOnMobile: { type: 'toggle', displayName: 'Show on mobile' }, }, - properties: {}, + properties: { + visibility: { + type: 'toggle', + displayName: 'Visibility', + validation: { + schema: { type: 'boolean' }, + defaultValue: true, + }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, events: {}, styles: { dividerColor: { @@ -21,14 +38,42 @@ export const verticalDividerConfig = { schema: { type: 'string' }, defaultValue: '#000000', }, + accordian: 'Divider', }, - visibility: { - type: 'toggle', - displayName: 'Visibility', + dividerStyle: { + type: 'switch', + displayName: 'Style', validation: { - schema: { type: 'boolean' }, - defaultValue: true, + schema: { type: 'string' }, }, + options: [ + { displayName: 'Solid', value: 'solid' }, + { displayName: 'Dashed', value: 'dashed' }, + ], + accordian: 'Divider', + }, + boxShadow: { + type: 'boxShadow', + displayName: 'Box Shadow', + validation: { + schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, + defaultValue: '0px 0px 0px 0px #00000040', + }, + accordian: 'Divider', + }, + 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', }, }, exposedVariables: { @@ -39,11 +84,16 @@ export const verticalDividerConfig = { showOnDesktop: { value: '{{true}}' }, showOnMobile: { value: '{{false}}' }, }, - properties: {}, + properties: { + visibility: { value: '{{true}}' }, + tooltip: { value: '' }, + }, events: [], styles: { - visibility: { value: '{{true}}' }, - dividerColor: { value: '#000000' }, + dividerColor: { value: '#CCD1D5' }, + dividerStyle: { value: 'solid' }, + padding: { value: 'default' }, + boxShadow: { value: '0px 0px 0px 0px #00000040' }, }, }, }; diff --git a/frontend/src/_helpers/editorHelpers.js b/frontend/src/_helpers/editorHelpers.js index 35335477d0..c3c18a6587 100644 --- a/frontend/src/_helpers/editorHelpers.js +++ b/frontend/src/_helpers/editorHelpers.js @@ -42,7 +42,7 @@ import { SvgImage } from '@/Editor/Components/SvgImage'; import { Html } from '@/Editor/Components/Html'; import { ButtonGroup } from '@/Editor/Components/ButtonGroup'; import { CustomComponent } from '@/Editor/Components/CustomComponent/CustomComponent'; -import { VerticalDivider } from '@/Editor/Components/verticalDivider'; +import { VerticalDivider } from '@/Editor/Components/VerticalDivider'; import { ColorPicker } from '@/Editor/Components/ColorPicker'; import { KanbanBoard } from '@/Editor/Components/KanbanBoard/KanbanBoard'; import { Kanban } from '@/Editor/Components/Kanban/Kanban'; diff --git a/frontend/src/_ui/Icon/solidIcons/AlignHorizontalCenter.jsx b/frontend/src/_ui/Icon/solidIcons/AlignHorizontalCenter.jsx new file mode 100644 index 0000000000..6b7b2f39ab --- /dev/null +++ b/frontend/src/_ui/Icon/solidIcons/AlignHorizontalCenter.jsx @@ -0,0 +1,16 @@ +import React from 'react'; + +const AlignHorizontalCenter = ({ fill = '', width = '25', className = '', viewBox = '0 0 25 25' }) => { + return ( + + + + ); +}; + +export default AlignHorizontalCenter; diff --git a/frontend/src/_ui/Icon/solidIcons/index.js b/frontend/src/_ui/Icon/solidIcons/index.js index 02ef072f4a..a64674b0bb 100644 --- a/frontend/src/_ui/Icon/solidIcons/index.js +++ b/frontend/src/_ui/Icon/solidIcons/index.js @@ -171,6 +171,7 @@ import WorkspaceConstants from './WorkspaceConstants.jsx'; import ArrowBackDown from './ArrowBackDown.jsx'; import AlignRightinspector from './AlignRightinspector.jsx'; import AlignLeftinspector from './AlignLeftinspector.jsx'; +import AlignHorizontalCenter from './AlignHorizontalCenter.jsx'; import AlignVerticallyTop from './AlignVerticallyTop.jsx'; import AlignVerticallyBottom from './AlignVerticallyBottom.jsx'; import AlignVerticallyCenter from './AlignVerticallyCenter.jsx'; @@ -242,9 +243,11 @@ const Icon = (props) => { case 'addrectangle': return ; case 'alignleftinspector': - return ; - case 'alignrightinspector': return ; + case 'alignrightinspector': + return ; + case 'alignhorizontalcenter': + return ; case 'alignverticallytop': return ; case 'alignverticallybottom': diff --git a/server/data-migrations/1743053824028-MoveVisibilityDisabledStatesDividerLink.ts b/server/data-migrations/1743053824028-MoveVisibilityDisabledStatesDividerLink.ts new file mode 100644 index 0000000000..21ff07dc0c --- /dev/null +++ b/server/data-migrations/1743053824028-MoveVisibilityDisabledStatesDividerLink.ts @@ -0,0 +1,64 @@ +import { Component } from '@entities/component.entity'; +import { processDataInBatches } from '@helpers/migration.helper'; +import { EntityManager, MigrationInterface, QueryRunner } from 'typeorm'; + +export class MoveVisibilityDisabledStatesDividerLink1743053824028 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + const componentTypes = ['Divider', 'VerticalDivider', 'Link']; + const batchSize = 100; + const entityManager = queryRunner.manager; + + for (const componentType of componentTypes) { + await processDataInBatches( + entityManager, + async (entityManager: EntityManager) => { + return await entityManager.find(Component, { + where: { type: componentType }, + order: { createdAt: 'ASC' }, + }); + }, + async (entityManager: EntityManager, components: Component[]) => { + await this.processUpdates(entityManager, components); + }, + batchSize + ); + } + } + + private async processUpdates(entityManager, components) { + for (const component of components) { + const properties = component.properties; + const styles = component.styles; + const general = component.general; + const generalStyles = component.generalStyles; + const validation = component.validation; + + if (styles.visibility) { + properties.visibility = styles.visibility; + delete styles.visibility; + } + + if (general?.tooltip) { + properties.tooltip = general?.tooltip; + delete general?.tooltip; + } + + if (generalStyles?.boxShadow) { + styles.boxShadow = generalStyles?.boxShadow; + delete generalStyles?.boxShadow; + } + + await entityManager.update(Component, component.id, { + properties, + styles, + general, + generalStyles, + validation, + }); + } + } + public async down(queryRunner: QueryRunner): Promise { + } + +} diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index abc2abce3e..6cd6b3ce8f 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -51,7 +51,7 @@ type DefaultDataSourceName = | 'tooljetdbdefault' | 'workflowsdefault'; -type NewRevampedComponent = 'Text' | 'TextInput' | 'PasswordInput' | 'NumberInput' | 'Table' | 'Button' | 'Checkbox'; +type NewRevampedComponent = 'Text' | 'TextInput' | 'PasswordInput' | 'NumberInput' | 'Table' | 'Button' | 'Checkbox' | 'Divider' | 'VerticalDivider' | 'Link'; const DefaultDataSourceNames: DefaultDataSourceName[] = [ 'restapidefault', @@ -69,6 +69,9 @@ const NewRevampedComponents: NewRevampedComponent[] = [ 'Table', 'Checkbox', 'Button', + 'Divider', + 'VerticalDivider', + 'Link', ]; @Injectable() @@ -79,7 +82,7 @@ export class AppImportExportService { protected appEnvironmentUtilService: AppEnvironmentUtilService, protected readonly entityManager: EntityManager, protected componentsService: ComponentsService - ) {} + ) { } async export(user: User, id: string, searchParams: any = {}): Promise<{ appV2: App }> { // https://github.com/typeorm/typeorm/issues/3857 @@ -181,13 +184,13 @@ export class AppImportExportService { const components = pages.length > 0 ? await manager - .createQueryBuilder(Component, 'components') - .leftJoinAndSelect('components.layouts', 'layouts') - .where('components.pageId IN(:...pageId)', { - pageId: pages.map((v) => v.id), - }) - .orderBy('components.created_at', 'ASC') - .getMany() + .createQueryBuilder(Component, 'components') + .leftJoinAndSelect('components.layouts', 'layouts') + .where('components.pageId IN(:...pageId)', { + pageId: pages.map((v) => v.id), + }) + .orderBy('components.created_at', 'ASC') + .getMany() : []; const events = await manager @@ -1056,10 +1059,10 @@ export class AppImportExportService { const options = importingDataSource.kind === 'tooljetdb' ? this.replaceTooljetDbTableIds( - importingQuery.options, - externalResourceMappings['tooljet_database'], - organizationId - ) + importingQuery.options, + externalResourceMappings['tooljet_database'], + organizationId + ) : importingQuery.options; const newQuery = manager.create(DataQuery, { @@ -1624,10 +1627,10 @@ export class AppImportExportService { options: dataSourceId == defaultDataSourceIds['tooljetdb'] ? this.replaceTooljetDbTableIds( - query.options, - externalResourceMappings['tooljet_database'], - user.organizationId - ) + query.options, + externalResourceMappings['tooljet_database'], + user.organizationId + ) : query.options, }); await manager.save(newQuery); diff --git a/server/src/modules/apps/services/widget-config/divider.js b/server/src/modules/apps/services/widget-config/divider.js index 3905c7583d..1c173fd54d 100644 --- a/server/src/modules/apps/services/widget-config/divider.js +++ b/server/src/modules/apps/services/widget-config/divider.js @@ -1,6 +1,6 @@ export const dividerConfig = { - name: 'Divider', - displayName: 'Divider', + name: 'HorizontalDivider', + displayName: 'Horizontal Divider', description: 'Separator between components', component: 'Divider', defaultSize: { @@ -11,15 +11,12 @@ export const dividerConfig = { showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' }, showOnMobile: { type: 'toggle', displayName: 'Show on mobile' }, }, - properties: {}, - events: {}, - styles: { - dividerColor: { - type: 'colorSwatches', - displayName: 'Divider color', + properties: { + label: { + type: 'code', + displayName: 'Label', validation: { schema: { type: 'string' }, - defaultValue: '#000000', }, }, visibility: { @@ -29,6 +26,109 @@ export const dividerConfig = { schema: { type: 'boolean' }, defaultValue: true, }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, + events: {}, + styles: { + dividerColor: { + type: 'colorSwatches', + displayName: 'Divider color', + validation: { + schema: { type: 'string' }, + }, + }, + visibility: { + type: 'toggle', + displayName: 'Visibility', + validation: { + schema: { type: 'boolean' }, + defaultValue: true, + }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, + events: {}, + styles: { + dividerColor: { + type: 'color', + displayName: 'Divider color', + validation: { + schema: { type: 'string' }, + defaultValue: '#000000', + }, + accordian: 'Divider', + }, + dividerStyle: { + type: 'switch', + displayName: 'Style', + validation: { + schema: { type: 'string' }, + }, + options: [ + { displayName: 'Solid', value: 'solid' }, + { displayName: 'Dashed', value: 'dashed' }, + ], + accordian: 'Divider', + }, + labelAlignment: { + type: 'switch', + displayName: 'Label alignment', + validation: { schema: { type: 'string' }, defaultValue: 'left' }, + isIcon: true, + showLabel: true, + options: [ + { displayName: 'alignleftinspector', value: 'left', iconName: 'alignleftinspector' }, + { displayName: 'alignhorizontalcenter', value: 'center', iconName: 'alignhorizontalcenter' }, + { displayName: 'alignrightinspector', value: 'right', iconName: 'alignrightinspector' }, + ], + accordian: 'Divider', + isFxNotRequired: true, + }, + labelColor: { + type: 'color', + displayName: 'Label Color', + validation: { + schema: { type: 'string' }, + }, + accordian: 'Divider', + }, + boxShadow: { + type: 'boxShadow', + displayName: 'Box Shadow', + validation: { + schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, + defaultValue: '0px 0px 0px 0px #00000040', + }, + accordian: 'Divider', + }, + 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', }, }, exposedVariables: { @@ -39,11 +139,19 @@ export const dividerConfig = { showOnDesktop: { value: '{{true}}' }, showOnMobile: { value: '{{false}}' }, }, - properties: {}, + properties: { + label: { value: '' }, + visibility: { value: '{{true}}' }, + tooltip: { value: '' }, + }, events: [], styles: { - visibility: { value: '{{true}}' }, - dividerColor: { value: '#000000' }, + dividerColor: { value: '#CCD1D5' }, + labelAlignment: { value: 'center' }, + dividerStyle: { value: 'solid' }, + labelColor: { value: '#6A727C' }, + padding: { value: 'default' }, + boxShadow: { value: '0px 0px 0px 0px #00000040' }, }, }, }; diff --git a/server/src/modules/apps/services/widget-config/verticalDivider.js b/server/src/modules/apps/services/widget-config/verticalDivider.js index e43b81adf7..df426c7b5f 100644 --- a/server/src/modules/apps/services/widget-config/verticalDivider.js +++ b/server/src/modules/apps/services/widget-config/verticalDivider.js @@ -1,17 +1,34 @@ export const verticalDividerConfig = { name: 'VerticalDivider', - displayName: 'Vertical Divider', + displayName: 'Vertical divider', description: 'Vertical line separator', component: 'VerticalDivider', defaultSize: { - width: 2, + width: 1, height: 100, }, others: { showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' }, showOnMobile: { type: 'toggle', displayName: 'Show on mobile' }, }, - properties: {}, + properties: { + visibility: { + type: 'toggle', + displayName: 'Visibility', + validation: { + schema: { type: 'boolean' }, + defaultValue: true, + }, + section: 'additionalActions', + }, + tooltip: { + type: 'code', + displayName: 'Tooltip', + validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' }, + section: 'additionalActions', + placeholder: 'Enter tooltip text', + }, + }, events: {}, styles: { dividerColor: { @@ -21,14 +38,42 @@ export const verticalDividerConfig = { schema: { type: 'string' }, defaultValue: '#000000', }, + accordian: 'Divider', }, - visibility: { - type: 'toggle', - displayName: 'Visibility', + dividerStyle: { + type: 'switch', + displayName: 'Style', validation: { - schema: { type: 'boolean' }, - defaultValue: true, + schema: { type: 'string' }, }, + options: [ + { displayName: 'Solid', value: 'solid' }, + { displayName: 'Dashed', value: 'dashed' }, + ], + accordian: 'Divider', + }, + boxShadow: { + type: 'boxShadow', + displayName: 'Box Shadow', + validation: { + schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, + defaultValue: '0px 0px 0px 0px #00000040', + }, + accordian: 'Divider', + }, + 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', }, }, exposedVariables: { @@ -39,11 +84,16 @@ export const verticalDividerConfig = { showOnDesktop: { value: '{{true}}' }, showOnMobile: { value: '{{false}}' }, }, - properties: {}, + properties: { + visibility: { value: '{{true}}' }, + tooltip: { value: '' }, + }, events: [], styles: { - visibility: { value: '{{true}}' }, - dividerColor: { value: '#000000' }, + dividerColor: { value: '#CCD1D5' }, + dividerStyle: { value: 'solid' }, + padding: { value: 'default' }, + boxShadow: { value: '0px 0px 0px 0px #00000040' }, }, }, };