-
- Menu
-
-
setHamburgerMenuOpen(false)} className="col-1 cursor-pointer">
-
+
@@ -237,12 +270,12 @@ const MobileNavigationMenu = ({ pages, switchPage, currentPageId, darkMode, chan
handlepageSwitch(page?.id)}
- className={`viewer-page-handler mb-2 cursor-pointer ${darkMode && 'dark'}`}
+ className={`viewer-page-handler cursor-pointer ${darkMode && 'dark'}`}
>
-
+
-
- {_.truncate(page?.name, { length: 22 })}
+
+ {_.truncate(page?.name, { length: 22 })}
@@ -254,16 +287,12 @@ const MobileNavigationMenu = ({ pages, switchPage, currentPageId, darkMode, chan
{showDarkModeToggle && (
-
-
+
diff --git a/frontend/src/AppBuilder/Viewer/PageGroup.jsx b/frontend/src/AppBuilder/Viewer/PageGroup.jsx
deleted file mode 100644
index 9948651c43..0000000000
--- a/frontend/src/AppBuilder/Viewer/PageGroup.jsx
+++ /dev/null
@@ -1,219 +0,0 @@
-/* eslint-disable import/namespace */
-import React, { useRef, useState } from 'react';
-import _ from 'lodash';
-import * as Icons from '@tabler/icons-react';
-// eslint-disable-next-line import/no-unresolved
-import FolderList from '@/_ui/FolderList/FolderList';
-import useStore from '@/AppBuilder/_stores/store';
-import { buildTree } from '../LeftSidebar/PageMenu/Tree/utilities';
-import OverflowTooltip from '@/_components/OverflowTooltip';
-import cx from 'classnames';
-import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
-
-const RenderPage = ({ page, currentPageId, switchPageWrapper, labelStyle, computeStyles, darkMode, homePageId }) => {
- const isHomePage = page.id === homePageId;
- const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
- const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
- return (page.hidden || page.disabled) && page?.restricted ? null : (
-
switchPageWrapper(page?.id)}
- selectedItem={page?.id === currentPageId}
- CustomIcon={!labelStyle?.icon?.hidden && IconElement}
- customStyles={computeStyles}
- darkMode={darkMode}
- >
- {!labelStyle?.label?.hidden && (
-
-
- {page.name}
-
-
- )}
-
- );
-};
-
-const RenderPageGroup = ({
- pages,
- pageGroup,
- currentPage,
- labelStyle,
- computeStyles,
- darkMode,
- switchPageWrapper,
- homePageId,
- currentPageId,
-}) => {
- const [hovered, setHovered] = useState(false);
- const [isExpanded, setIsExpanded] = useState(true);
- const contentRef = useRef(null);
-
- const IconElement = Icons?.[pageGroup.icon] ?? Icons?.['IconHome2'];
-
- const handleToggle = () => {
- setIsExpanded(!isExpanded);
- };
-
- if (labelStyle?.label?.hidden) {
- return (
- <>
- {pages.map((page) => (
-
- ))}
- >
- );
- }
-
- const active = currentPage.pageGroupId === pageGroup.id;
-
- return (
-
-
-
-
- {!labelStyle?.label?.hidden && (
-
-
- {pageGroup.name}
-
-
- )}
-
-
-
-
-
- {pages.map((page) => (
-
- ))}
-
-
-
- );
-};
-
-export const RenderPageAndPageGroup = ({ pages, labelStyle, computeStyles, darkMode, switchPageWrapper }) => {
- // Don't render empty folders if displaying only icons
- const { moduleId } = useModuleContext();
- const tree = buildTree(pages, !!labelStyle?.label?.hidden);
- const filteredPages = tree.filter((page) => (!page?.isPageGroup || page.children?.length > 0) && !page?.restricted);
- const currentPageId = useStore((state) => state.currentPageId);
- const currentPage = pages.find((page) => page.id === currentPageId);
- const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
- return (
-
- {/*
page.id)}> */}
- {filteredPages.map((page, index) => {
- if (
- page.isPageGroup &&
- page.children.length === 0 &&
- labelStyle?.label?.hidden &&
- !page.children.some((child) => child?.restricted === true)
- ) {
- return null;
- }
- if (page.children && page.isPageGroup && !page.children.some((child) => child?.restricted === true)) {
- // if we are only displaying icons, we don't display the groups instead display separator to separate a page groups
- const renderSeparatorTop = index !== 0 && labelStyle?.label?.hidden;
- const renderSeparatorBottom = !filteredPages[index + 1]?.isPageGroup && labelStyle?.label?.hidden;
- return (
- <>
- {renderSeparatorTop && (
-
- )}
-
- {renderSeparatorBottom && (
-
- )}
- >
- );
- } else if (!page.isPageGroup) {
- return (
-
- );
- }
- })}
- {/* */}
-
- );
-};
diff --git a/frontend/src/AppBuilder/Viewer/PreviewSettings.jsx b/frontend/src/AppBuilder/Viewer/PreviewSettings.jsx
index e914a9bee4..cc1fd83430 100644
--- a/frontend/src/AppBuilder/Viewer/PreviewSettings.jsx
+++ b/frontend/src/AppBuilder/Viewer/PreviewSettings.jsx
@@ -71,7 +71,7 @@ const PreviewSettings = ({ isMobileLayout, showHeader, darkMode }) => {
onClick={props.onClick}
data-cy="preview-settings"
>
-
+
)}
@@ -125,7 +125,7 @@ const PreviewSettings = ({ isMobileLayout, showHeader, darkMode }) => {
-
+
diff --git a/frontend/src/AppBuilder/Viewer/Viewer.jsx b/frontend/src/AppBuilder/Viewer/Viewer.jsx
index 2995858f1a..a9b8cdc856 100644
--- a/frontend/src/AppBuilder/Viewer/Viewer.jsx
+++ b/frontend/src/AppBuilder/Viewer/Viewer.jsx
@@ -11,11 +11,12 @@ import { HTML5Backend } from 'react-dnd-html5-backend';
import AppCanvas from '@/AppBuilder/AppCanvas';
import DesktopHeader from './DesktopHeader';
import MobileHeader from './MobileHeader';
-import ViewerSidebarNavigation from './ViewerSidebarNavigation';
import { shallow } from 'zustand/shallow';
import Popups from '../Popups';
import { ModuleProvider } from '@/AppBuilder/_contexts/ModuleContext';
+import { getPatToken, setPatToken } from '@/AppBuilder/EmbedApp';
import Spinner from '@/_ui/Spinner';
+import toast from 'react-hot-toast';
export const Viewer = ({
id: appId,
@@ -48,6 +49,7 @@ export const Viewer = ({
isMaintenanceOn,
setIsViewer,
toggleCurrentLayout,
+ isReleasedVersionId,
} = useStore(
(state) => ({
isEditorLoading: state.loaderStore.modules[moduleId].isEditorLoading,
@@ -68,6 +70,7 @@ export const Viewer = ({
isMaintenanceOn: state.appStore.modules[moduleId].app.isMaintenanceOn,
setIsViewer: state.setIsViewer,
toggleCurrentLayout: state.toggleCurrentLayout,
+ isReleasedVersionId: state?.releasedVersionId == state.currentVersionId || state.isVersionReleased,
}),
shallow
);
@@ -100,6 +103,9 @@ export const Viewer = ({
localStorage.setItem('isPagesSidebarPinned', JSON.stringify(newValue));
}, [isSidebarPinned]);
+ const { definition: { properties = {} } = {} } = pageSettings ?? {};
+ const { position, hideHeader } = properties ?? {};
+
const canvasRef = useRef(null);
const isLoading = false;
const isMobilePreviewMode = selectedVersion?.id && currentLayout === 'mobile';
@@ -115,6 +121,17 @@ export const Viewer = ({
console.log('setAppVersionCurrentEnvironment', environment);
}, []);
+ useEffect(() => {
+ if (window.name && !getPatToken()) {
+ try {
+ const patToken = window.name;
+ setPatToken(patToken); // restore it in memory
+ } catch (e) {
+ console.error('Invalid PAT in window.name');
+ }
+ }
+ }, []);
+
useEffect(() => {
updateCanvasHeight(currentPageComponents, moduleId);
}, [currentPageComponents, moduleId, updateCanvasHeight]);
@@ -193,7 +210,12 @@ export const Viewer = ({
Loading...}>
@@ -207,8 +229,8 @@ export const Viewer = ({
}}
>
- {currentLayout !== 'mobile' && !hideSidebar && !moduleMode && (
-
- )}
+ )} */}
- {currentLayout === 'mobile' && isMobilePreviewMode && !moduleMode && (
+ {currentLayout === 'mobile' && isMobilePreviewMode && (
)}
{isMobilePreviewMode &&
}
@@ -270,11 +301,11 @@ export const Viewer = ({
-
-
+
+
-
-
+
+
);
}
};
diff --git a/frontend/src/AppBuilder/Viewer/ViewerSidebarNavigation.jsx b/frontend/src/AppBuilder/Viewer/ViewerSidebarNavigation.jsx
deleted file mode 100644
index 6a64c6766b..0000000000
--- a/frontend/src/AppBuilder/Viewer/ViewerSidebarNavigation.jsx
+++ /dev/null
@@ -1,180 +0,0 @@
-import React from 'react';
-import _ from 'lodash';
-import cx from 'classnames';
-import * as Icons from '@tabler/icons-react';
-// eslint-disable-next-line import/no-unresolved
-import FolderList from '@/_ui/FolderList/FolderList';
-import { ButtonSolid } from '@/_ui/AppButton/AppButton';
-import useStore from '@/AppBuilder/_stores/store';
-import { APP_HEADER_HEIGHT } from '../AppCanvas/appCanvasConstants';
-import OverflowTooltip from '@/_components/OverflowTooltip';
-import { RenderPageAndPageGroup } from './PageGroup';
-import { useModuleContext } from '@/AppBuilder/_contexts/ModuleContext';
-
-export const ViewerSidebarNavigation = ({
- isMobileDevice,
- pages,
- currentPageId,
- switchPage,
- darkMode,
- showHeader,
- isSidebarPinned,
- toggleSidebarPinned,
-}) => {
- const { moduleId } = useModuleContext();
- const { definition: { styles = {}, properties = {} } = {} } = useStore((state) => state.pageSettings) || {};
- const selectedVersionName = useStore((state) => state.selectedVersion?.name);
- const selectedEnvironmentName = useStore((state) => state.selectedEnvironment?.name);
- const homePageId = useStore((state) => state.appStore.modules[moduleId].app.homePageId);
- const license = useStore((state) => state.license);
-
- if (isMobileDevice) {
- return null;
- }
- const computeStyles = (isSelected, isHovered) => {
- const baseStyles = {
- pill: {
- borderRadius: `${styles.pillRadius.value}px`,
- },
- icon: {
- color: !styles.iconColor.isDefault && styles.iconColor.value,
- fill: !styles.iconColor.isDefault && styles.iconColor.value,
- },
- };
-
- switch (true) {
- case isSelected: {
- return {
- ...baseStyles,
- text: {
- color: !styles.selectedTextColor.isDefault && styles.selectedTextColor.value,
- },
- icon: {
- stroke: !styles.selectedIconColor.isDefault && styles.selectedIconColor.value,
- color: !styles.selectedIconColor.isDefault && styles.selectedIconColor.value,
- fill: !styles.selectedIconColor.isDefault && styles.selectedIconColor.value,
- },
- pill: {
- background: !styles.pillSelectedBackgroundColor.isDefault && styles.pillSelectedBackgroundColor.value,
- ...baseStyles.pill,
- },
- };
- }
- case isHovered: {
- return {
- ...baseStyles,
- pill: {
- background: !styles.pillHoverBackgroundColor.isDefault && styles.pillHoverBackgroundColor.value,
- ...baseStyles.pill,
- },
- };
- }
- default: {
- return {
- text: {
- color: !styles.textColor.isDefault && styles.textColor.value,
- },
- icon: {
- color: !styles.iconColor.isDefault && styles.iconColor.value,
- fill: !styles.iconColor.isDefault && styles.iconColor.value,
- },
- };
- }
- }
- };
-
- const labelStyle = {
- icon: {
- hidden: properties?.style === 'text',
- },
- label: {
- hidden: properties?.style === 'icon',
- },
- };
-
- const switchPageWrapper = (pageId) => {
- const queryParams = {
- version: selectedVersionName,
- env: selectedEnvironmentName,
- };
- switchPage(pageId, pages.find((page) => page.id === pageId)?.handle, Object.entries(queryParams), moduleId);
- };
-
- const isLicensed =
- !_.get(license, 'featureAccess.licenseStatus.isExpired', true) &&
- _.get(license, 'featureAccess.licenseStatus.isLicenseValid', false);
-
- return (
-
-
-
{
- toggleSidebarPinned();
- }}
- as="a"
- variant="tertiary"
- className={cx('left-sidebar-header-btn pin', { 'd-none': !properties?.collapsable })}
- fill={`var(--slate12)`}
- darkMode={darkMode}
- leftIcon={isSidebarPinned ? 'unpin01' : 'pin'}
- iconWidth="18"
- >
- {isLicensed ? (
-
- ) : (
-
- {pages.map((page) => {
- const isHomePage = page.id === homePageId;
- const iconName = isHomePage && !page.icon ? 'IconHome2' : page.icon;
- // eslint-disable-next-line import/namespace
- const IconElement = Icons?.[iconName] ?? Icons?.['IconFileDescription'];
- return page.hidden || page.disabled || page?.restricted ? null : (
- switchPageWrapper(page?.id)}
- selectedItem={page?.id === currentPageId}
- CustomIcon={!labelStyle?.icon?.hidden && IconElement}
- customStyles={computeStyles}
- darkMode={darkMode}
- >
- {!labelStyle?.label?.hidden && (
-
-
- {page.name}
-
-
- )}
-
- );
- })}
-
- )}
-
-
- );
-};
-
-export default ViewerSidebarNavigation;
diff --git a/frontend/src/AppBuilder/Viewer/viewer.scss b/frontend/src/AppBuilder/Viewer/viewer.scss
index 5f70a4a19f..30d01411db 100644
--- a/frontend/src/AppBuilder/Viewer/viewer.scss
+++ b/frontend/src/AppBuilder/Viewer/viewer.scss
@@ -52,9 +52,17 @@
.released-version-no-header-mbl-preview {
position: absolute;
left: 50%;
- border-radius: 100px;
padding : 2px 8px;
+ background-color: unset !important;
z-index: 1000;
+
+ .preview-chip {
+ color: var(--text-on-solid) !important;
+ }
+ .preview-settings {
+ margin-left: 6px;
+ padding: 4px;
+ }
}
.preview-settings-overlay {
@@ -121,11 +129,6 @@
z-index: 1201;
}
-.bm-menu-wrap,
-.bm-overlay {
- right: calc(50vw - 225px) !important;
- width: calc(450px - 68px) !important;
-}
.powered-with-tj {
cursor: pointer;
@@ -160,6 +163,39 @@
width: 100%;
}
+ &.mobile-view {
+ .navbar, .header {
+ height: 60px !important;
+ max-height: 60px !important;
+ }
+ .header {
+ box-shadow: var(--elevation-100-box-shadow);
+ }
+ .preview-settings-mobile {
+ height: 44px !important;
+ header {
+ height: 44px !important;
+
+ .header-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: unset !important;
+ padding: 0px !important;
+
+ .released-version-no-header-mbl-preview {
+ position: unset !important;
+ }
+ }
+ }
+ }
+
+ .mobile-nav-container {
+ .header-container {
+ background-color: unset !important;
+ }
+ }
+ }
.canvas-container::-webkit-scrollbar {
// width: 0;
@@ -178,8 +214,6 @@
#page-settings-tabpane-styles {
.accordion-item {
- margin-bottom: 10px;
- border-radius: 5px;
overflow: hidden;
}
@@ -187,7 +221,6 @@
width: 100%;
text-align: left;
border: none;
- padding: 10px 15px;
font-size: 16px;
cursor: pointer;
display: flex;
@@ -197,11 +230,10 @@
}
.page-group-collapse{
- bottom: 7px;
- right: 12px;
- position: absolute;
+ // right: 12px;
+ // position: absolute;
display: block !important;
&.expanded{
- transform: rotate(60deg);
+ transform: rotate(0deg) !important;
}
}
\ No newline at end of file
diff --git a/frontend/src/AppBuilder/WidgetManager/configs/widgetConfig.js b/frontend/src/AppBuilder/WidgetManager/configs/widgetConfig.js
index 21c68480ea..00ad0ab573 100644
--- a/frontend/src/AppBuilder/WidgetManager/configs/widgetConfig.js
+++ b/frontend/src/AppBuilder/WidgetManager/configs/widgetConfig.js
@@ -66,68 +66,95 @@ import {
} from '../widgets';
export const widgets = [
- tableConfig,
+ // Buttons
buttonConfig,
+ buttonGroupConfig,
+
+ //Data
+ tableConfig,
chartConfig,
- modalConfig,
- modalV2Config,
+
+ // Layouts
formConfig,
+ modalV2Config,
+ containerConfig,
+ tabsConfig,
+ listviewConfig,
+ calendarConfig,
+ kanbanConfig,
+
+ //Text inputs
textinputConfig,
- numberinputConfig,
- passinputConfig,
emailinputConfig,
+ passinputConfig,
+ textareaConfig,
+ richtextareaConfig,
+
+ //Number inputs
+ numberinputConfig,
phoneinputConfig,
currencyinputConfig,
- datepickerConfig,
- datetimePickerV2Config,
+ rangeSliderConfig,
+ starratingConfig,
+
+ //Select inputs
+ dropdownV2Config,
+ multiselectV2Config,
+ checkboxConfig,
+ toggleSwitchV2Config,
+ radiobuttonV2Config,
+ treeSelectConfig,
+
+ //Date and time inputs
datePickerV2Config,
timePickerConfig,
- checkboxConfig,
- radiobuttonConfig,
- radiobuttonV2Config,
- toggleswitchConfig,
- toggleSwitchV2Config,
- textareaConfig,
+ datetimePickerV2Config,
daterangepickerConfig,
- textConfig,
- imageConfig,
- containerConfig,
- dropdownConfig,
- dropdownV2Config,
- multiselectConfig,
- multiselectV2Config,
- richtextareaConfig,
- mapConfig,
- qrscannerConfig,
- starratingConfig,
- dividerConfig,
- filepickerConfig,
- calendarConfig,
- iframeConfig,
- codeEditorConfig,
- tabsConfig,
- timerConfig,
- listviewConfig,
- tagsConfig,
- paginationConfig,
- circularProgressbarConfig,
- spinnerConfig,
- statisticsConfig,
- rangeSliderConfig,
- timelineConfig,
- svgImageConfig,
- htmlConfig,
- verticalDividerConfig,
- customComponentConfig,
- buttonGroupConfig,
- pdfConfig,
- stepsConfig,
- kanbanConfig,
- colorPickerConfig,
- treeSelectConfig,
+
+ //Navigation
linkConfig,
+ stepsConfig,
+ paginationConfig,
+
+ //Media
iconConfig,
+ imageConfig,
+ svgImageConfig,
+ pdfConfig,
+ mapConfig,
+
+ //Presentation
+ textConfig,
+ tagsConfig,
+ circularProgressbarConfig,
+ dividerConfig,
+ verticalDividerConfig,
+ statisticsConfig,
+ timelineConfig,
+ timerConfig,
+ spinnerConfig,
+
+ //Custom
+ customComponentConfig,
+ htmlConfig,
+ iframeConfig,
+
+ //Miscellaneous
+ filepickerConfig,
+ codeEditorConfig,
+ colorPickerConfig,
boundedBoxConfig,
+ qrscannerConfig,
+
+ //Legacy
+ modalConfig,
+ datepickerConfig,
+ radiobuttonConfig,
+ toggleswitchConfig,
+ dropdownConfig,
+ multiselectConfig,
+
+ //Module
moduleContainerConfig,
moduleViewerConfig,
];
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/button.js b/frontend/src/AppBuilder/WidgetManager/widgets/button.js
index d5b6a58214..b945b737ed 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/button.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/button.js
@@ -219,11 +219,11 @@ export const buttonConfig = {
events: [],
styles: {
textColor: { value: '#FFFFFF' },
- borderColor: { value: 'var(--primary-brand)' },
- loaderColor: { value: '#FFFFFF' },
+ borderColor: { value: 'var(--cc-primary-brand)' },
+ loaderColor: { value: 'var(--cc-surface1-surface)' },
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: 'var(--primary-brand)' },
- iconColor: { value: '#FFFFFF' },
+ backgroundColor: { value: 'var(--cc-primary-brand)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000090' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/buttonGroup.js b/frontend/src/AppBuilder/WidgetManager/widgets/buttonGroup.js
index 24690ebfca..72f675df97 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/buttonGroup.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/buttonGroup.js
@@ -120,7 +120,7 @@ export const buttonGroupConfig = {
displayName: 'Selected background color',
validation: {
schema: { type: 'string' },
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-primary-brand)',
},
},
alignment: {
@@ -169,14 +169,14 @@ export const buttonGroupConfig = {
},
events: [],
styles: {
- backgroundColor: { value: '' },
- textColor: { value: '' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ textColor: { value: 'var(--cc-primary-text)' },
visibility: { value: '{{true}}' },
borderRadius: { value: '{{4}}' },
disabledState: { value: '{{false}}' },
selectedTextColor: { value: '#FFFFFF' },
padding: { value: 'default' },
- selectedBackgroundColor: { value: 'var(--primary-brand)' },
+ selectedBackgroundColor: { value: 'var(--cc-primary-brand)' },
alignment: { value: 'left' },
},
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/chart.js b/frontend/src/AppBuilder/WidgetManager/widgets/chart.js
index 81dbd2547a..66b5b21e98 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/chart.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/chart.js
@@ -45,7 +45,7 @@ export const chartConfig = {
schema: {
type: 'string',
},
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-primary-brand)',
},
},
showAxes: {
@@ -136,7 +136,7 @@ export const chartConfig = {
backgroundColor: {
type: 'colorSwatches',
displayName: 'Background color',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
},
padding: {
type: 'code',
@@ -192,7 +192,7 @@ export const chartConfig = {
},
properties: {
title: { value: 'This title can be changed' },
- markerColor: { value: 'var(--primary-brand)' },
+ markerColor: { value: 'var(--cc-primary-brand)' },
showAxes: { value: '{{true}}' },
showGridLines: { value: '{{true}}' },
plotFromJson: { value: '{{false}}' },
@@ -228,7 +228,7 @@ export const chartConfig = {
},
events: [],
styles: {
- backgroundColor: { value: '#fff' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
padding: { value: '50' },
borderRadius: { value: '{{4}}' },
visibility: { value: '{{true}}' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/checkbox.js b/frontend/src/AppBuilder/WidgetManager/widgets/checkbox.js
index ca4e740885..bff6b026d8 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/checkbox.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/checkbox.js
@@ -196,11 +196,11 @@ export const checkboxConfig = {
events: [],
styles: {
disabledState: { value: '{{false}}' },
- textColor: { value: '#1B1F24' },
- checkboxColor: { value: 'var(--primary-brand)' },
- uncheckedColor: { value: '#E4E7EB' },
- borderColor: { value: '#CCD1D5' },
- handleColor: { value: '#FFFFFF' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ checkboxColor: { value: 'var(--cc-primary-brand)' },
+ uncheckedColor: { value: 'var(--cc-surface1-surface)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ handleColor: { value: 'var(--cc-surface1-surface)' },
alignment: { value: 'right' },
boxShadow: { value: '0px 0px 0px 0px #00000090' },
padding: { value: 'default' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/circularProgressbar.js b/frontend/src/AppBuilder/WidgetManager/widgets/circularProgressbar.js
index 2babc27a12..ee30a2c2a4 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/circularProgressbar.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/circularProgressbar.js
@@ -33,10 +33,10 @@ export const circularProgressbarConfig = {
styles: {
color: {
type: 'colorSwatches',
- displayName: 'colorSwatches',
+ displayName: 'Color',
validation: {
schema: { type: 'string' },
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-primary-brand)',
},
},
textColor: {
@@ -44,7 +44,7 @@ export const circularProgressbarConfig = {
displayName: 'Text Color',
validation: {
schema: { type: 'string' },
- defaultValue: '#fff',
+ defaultValue: 'var(--cc-primary-text)',
},
},
textSize: {
@@ -104,8 +104,8 @@ export const circularProgressbarConfig = {
},
events: [],
styles: {
- color: { value: 'var(--primary-brand)' },
- textColor: { value: '' },
+ color: { value: 'var(--cc-primary-brand)' },
+ textColor: { value: 'var(--cc-primary-text)' },
textSize: { value: '{{16}}' },
strokeWidth: { value: '{{8}}' },
counterClockwise: { value: '{{false}}' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/codeEditor.js b/frontend/src/AppBuilder/WidgetManager/widgets/codeEditor.js
index eb76891af0..45386c8a33 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/codeEditor.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/codeEditor.js
@@ -20,6 +20,15 @@ export const codeEditorConfig = {
defaultValue: true,
},
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
mode: {
type: 'code',
displayName: 'Mode',
@@ -80,6 +89,7 @@ export const codeEditorConfig = {
showOnMobile: { value: '{{false}}' },
},
properties: {
+ dynamicHeight: { value: '{{false}}' },
enableLineNumber: { value: '{{true}}' },
mode: { value: 'javascript' },
placeholder: { value: '' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/colorPicker.js b/frontend/src/AppBuilder/WidgetManager/widgets/colorPicker.js
index 6255f81202..10ade7bd76 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/colorPicker.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/colorPicker.js
@@ -4,7 +4,7 @@ export const colorPickerConfig = {
description: 'Choose colors from a palette',
component: 'ColorPicker',
properties: {
- defaultColor: { type: 'colorSwatches', displayName: 'Default color' },
+ defaultColor: { type: 'color', displayName: 'Default color' },
},
defaultSize: {
width: 9,
@@ -14,9 +14,7 @@ export const colorPickerConfig = {
{
displayName: 'Set Color',
handle: 'setColor',
- params: [
- { handle: 'colorSwatches', displayName: 'colorSwatches', defaultValue: '#ffffff', type: 'colorSwatches' },
- ],
+ params: [{ handle: 'color', displayName: 'Color', defaultValue: '#ffffff', type: 'color' }],
},
],
others: {
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/container.js b/frontend/src/AppBuilder/WidgetManager/widgets/container.js
index 04ddf805d9..545d772829 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/container.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/container.js
@@ -21,6 +21,15 @@ export const containerConfig = {
defaultValue: false,
},
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
visibility: {
type: 'toggle',
displayName: 'Visibility',
@@ -47,11 +56,6 @@ export const containerConfig = {
defaultValue: true,
},
},
- headerHeight: {
- type: 'numberInput',
- displayName: 'Header height',
- validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 80 },
- },
},
defaultChildren: [
{
@@ -61,17 +65,18 @@ export const containerConfig = {
top: 20,
left: 1,
height: 40,
+ width: 20,
},
displayName: 'ContainerText',
properties: ['text'],
- slotName: 'header',
accessorKey: 'text',
- styles: ['fontWeight', 'textSize', 'textColor'],
+ styles: ['fontWeight', 'textSize', 'textColor', 'boxShadow'],
defaultValue: {
text: 'Container title',
fontWeight: 'bold',
textSize: 16,
- textColor: '#000',
+ textColor: 'var(--cc-primary-text)',
+ boxShadow: '0px 0px 0px 0px #00000090',
},
},
],
@@ -82,7 +87,7 @@ export const containerConfig = {
displayName: 'Background',
validation: {
schema: { type: 'string' },
- defaultValue: '#fff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
accordian: 'container',
},
@@ -91,7 +96,7 @@ export const containerConfig = {
displayName: 'Background',
validation: {
schema: { type: 'string' },
- defaultValue: '#ddd',
+ defaultValue: 'var(--cc-surface1-surface)',
},
accordian: 'header',
},
@@ -100,19 +105,19 @@ export const containerConfig = {
displayName: 'Border color',
validation: {
schema: { type: 'string' },
- defaultValue: '#fff',
+ defaultValue: 'var(--cc-default-border)',
},
accordian: 'container',
},
borderRadius: {
type: 'numberInput',
- displayName: 'Border',
+ displayName: 'Border radius',
validation: {
schema: {
type: 'union',
schemas: [{ type: 'string' }, { type: 'number' }],
},
- defaultValue: 4,
+ defaultValue: 6,
},
accordian: 'container',
},
@@ -155,15 +160,16 @@ export const containerConfig = {
loadingState: { value: `{{false}}` },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
+ dynamicHeight: { value: '{{false}}' },
headerHeight: { value: `{{80}}` },
},
events: [],
styles: {
- backgroundColor: { value: '#fff' },
- headerBackgroundColor: { value: '#fff' },
- borderRadius: { value: '4' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ headerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ borderRadius: { value: '6' },
headerHeight: { value: '{{80}}' },
- borderColor: { value: '#fff' },
+ borderColor: { value: 'var(--cc-default-border)' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
},
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/currencyinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/currencyinput.js
index 64a8f2df57..efd53844f9 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/currencyinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/currencyinput.js
@@ -88,9 +88,9 @@ export const currencyinputConfig = {
},
styles: {
color: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -140,33 +140,33 @@ export const currencyinputConfig = {
},
backgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -177,9 +177,9 @@ export const currencyinputConfig = {
visibility: false,
},
iconColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Icon color',
- validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
accordian: 'field',
visibility: false,
showLabel: false,
@@ -284,17 +284,17 @@ export const currencyinputConfig = {
},
events: [],
styles: {
- textColor: { value: '#1B1F24' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- errTextColor: { value: '#D72D39' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
- iconColor: { value: '#CFD3D859' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
- color: { value: '#1B1F24' },
+ color: { value: 'var(--cc-primary-text)' },
auto: { value: '{{true}}' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/customComponent.js b/frontend/src/AppBuilder/WidgetManager/widgets/customComponent.js
index cc1dae2b3e..2677b71c25 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/customComponent.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/customComponent.js
@@ -37,9 +37,9 @@ export const customComponentConfig = {
value: `{{{ title: 'Hi! There', buttonText: 'Update Title'}}}`,
},
code: {
- value: `import React from 'https://cdn.skypack.dev/react';
- import ReactDOM from 'https://cdn.skypack.dev/react-dom';
- import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core';
+ value: `import React from 'https://esm.sh/react@17.0.2';
+ import ReactDOM from 'https://esm.sh/react-dom@17.0.2';
+ import { Button, Container } from 'https://esm.sh/@material-ui/core@4.12.4?deps=react@17.0.2';
const MyCustomComponent = ({data, updateData, runQuery}) => (
{data.title}
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/datepickerV2.js b/frontend/src/AppBuilder/WidgetManager/widgets/datepickerV2.js
index ea56598d2e..46a3c794c7 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/datepickerV2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/datepickerV2.js
@@ -170,8 +170,8 @@ export const datePickerV2Config = {
styles: {
labelColor: {
type: 'colorSwatches',
- displayName: 'colorSwatches',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ displayName: 'Color',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -222,31 +222,31 @@ export const datePickerV2Config = {
fieldBackgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
fieldBorderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
selectedTextColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#E54D2E' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -262,7 +262,7 @@ export const datePickerV2Config = {
showLabel: false,
validation: {
schema: { type: 'string' },
- defaultValue: '#6A727C',
+ defaultValue: 'var(--cc-default-icon)',
},
accordian: 'field',
},
@@ -334,23 +334,23 @@ export const datePickerV2Config = {
},
events: [],
styles: {
- labelColor: { value: '#1B1F24' },
+ labelColor: { value: 'var(--cc-primary-text)' },
alignment: { value: 'side' },
direction: { value: 'left' },
labelWidth: { value: '20' },
auto: { value: '{{true}}' },
- fieldBackgroundColor: { value: '#fff' },
- fieldBorderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- selectedTextColor: { value: '#1B1F24' },
- errTextColor: { value: '#E54D2E' },
+ fieldBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ fieldBorderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
icon: { value: 'IconCalendarEvent' },
iconVisibility: { value: true },
iconDirection: { value: 'left' },
fieldBorderRadius: { value: '{{6}}' },
boxShadow: { value: '0px 0px 0px 0px #121212' },
padding: { value: 'default' },
- iconColor: { value: '#6A727C' },
+ iconColor: { value: 'var(--cc-default-icon)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/daterangepicker.js b/frontend/src/AppBuilder/WidgetManager/widgets/daterangepicker.js
index 2fcd5bfb42..72fe4a52a8 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/daterangepicker.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/daterangepicker.js
@@ -200,8 +200,8 @@ export const daterangepickerConfig = {
styles: {
labelColor: {
type: 'colorSwatches',
- displayName: 'colorSwatches',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ displayName: 'Color',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -252,31 +252,31 @@ export const daterangepickerConfig = {
fieldBackgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
fieldBorderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
selectedTextColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#E54D2E' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -292,7 +292,7 @@ export const daterangepickerConfig = {
showLabel: false,
validation: {
schema: { type: 'string' },
- defaultValue: '#6A727C',
+ defaultValue: 'var(--cc-default-icon)',
},
accordian: 'field',
},
@@ -365,23 +365,23 @@ export const daterangepickerConfig = {
},
events: [],
styles: {
- labelColor: { value: '#1B1F24' },
+ labelColor: { value: 'var(--cc-primary-text)' },
alignment: { value: 'side' },
direction: { value: 'left' },
labelWidth: { value: '20' },
auto: { value: '{{true}}' },
- fieldBackgroundColor: { value: '#fff' },
- fieldBorderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- selectedTextColor: { value: '#1B1F24' },
- errTextColor: { value: '#E54D2E' },
+ fieldBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ fieldBorderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
icon: { value: 'IconCalendarMonth' },
iconVisibility: { value: true },
iconDirection: { value: 'left' },
borderRadius: { value: '{{6}}' },
boxShadow: { value: '0px 0px 0px 0px #121212' },
padding: { value: 'default' },
- iconColor: { value: '#6A727C' },
+ iconColor: { value: 'var(--cc-default-icon)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/datetimepickerV2.js b/frontend/src/AppBuilder/WidgetManager/widgets/datetimepickerV2.js
index 658cc31c01..a737486e3b 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/datetimepickerV2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/datetimepickerV2.js
@@ -215,8 +215,8 @@ export const datetimePickerV2Config = {
styles: {
labelColor: {
type: 'colorSwatches',
- displayName: 'colorSwatches',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ displayName: 'Color',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -267,31 +267,31 @@ export const datetimePickerV2Config = {
fieldBackgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
fieldBorderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
selectedTextColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#E54D2E' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -307,7 +307,7 @@ export const datetimePickerV2Config = {
showLabel: false,
validation: {
schema: { type: 'string' },
- defaultValue: '#6A727C',
+ defaultValue: 'var(--cc-default-icon)',
},
accordian: 'field',
},
@@ -385,23 +385,23 @@ export const datetimePickerV2Config = {
},
events: [],
styles: {
- labelColor: { value: '#1B1F24' },
+ labelColor: { value: 'var(--cc-primary-text)' },
alignment: { value: 'side' },
direction: { value: 'left' },
labelWidth: { value: '20' },
auto: { value: '{{true}}' },
- fieldBackgroundColor: { value: '#fff' },
- fieldBorderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- selectedTextColor: { value: '#1B1F24' },
- errTextColor: { value: '#E54D2E' },
+ fieldBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ fieldBorderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
icon: { value: 'IconCalendarTime' },
iconVisibility: { value: true },
iconDirection: { value: 'left' },
fieldBorderRadius: { value: '{{6}}' },
boxShadow: { value: '0px 0px 0px 0px #121212' },
padding: { value: 'default' },
- iconColor: { value: '#6A727C' },
+ iconColor: { value: 'var(--cc-default-icon)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/divider.js b/frontend/src/AppBuilder/WidgetManager/widgets/divider.js
index 33b64d9f56..378ca06a02 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/divider.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/divider.js
@@ -65,11 +65,11 @@ export const dividerConfig = {
events: {},
styles: {
dividerColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Divider color',
validation: {
schema: { type: 'string' },
- defaultValue: '#000000',
+ defaultValue: 'var(--cc-default-border)',
},
accordian: 'Divider',
},
@@ -100,7 +100,7 @@ export const dividerConfig = {
isFxNotRequired: true,
},
labelColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Label Color',
validation: {
schema: { type: 'string' },
@@ -146,10 +146,10 @@ export const dividerConfig = {
},
events: [],
styles: {
- dividerColor: { value: '#CCD1D5' },
+ dividerColor: { value: 'var(--cc-default-border)' },
labelAlignment: { value: 'center' },
dividerStyle: { value: 'solid' },
- labelColor: { value: '#6A727C' },
+ labelColor: { value: 'var(--cc-placeholder-text)' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/dropdown.js b/frontend/src/AppBuilder/WidgetManager/widgets/dropdown.js
index b8b090af24..d4424e23fb 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/dropdown.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/dropdown.js
@@ -134,7 +134,7 @@ export const dropdownConfig = {
schema: {
type: 'string',
},
- defaultValue: '#000000',
+ defaultValue: 'var(--cc-primary-text)',
},
},
disabledState: {
@@ -200,6 +200,7 @@ export const dropdownConfig = {
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
justifyContent: { value: 'left' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/dropdownV2.js b/frontend/src/AppBuilder/WidgetManager/widgets/dropdownV2.js
index d7534b25a8..473985efbe 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/dropdownV2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/dropdownV2.js
@@ -127,7 +127,7 @@ export const dropdownV2Config = {
labelColor: {
type: 'colorSwatches',
displayName: 'Color',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -179,31 +179,31 @@ export const dropdownV2Config = {
fieldBackgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
fieldBorderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
selectedTextColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -335,14 +335,14 @@ export const dropdownV2Config = {
},
events: [],
styles: {
- labelColor: { value: '#1B1F24' },
+ labelColor: { value: 'var(--cc-primary-text)' },
labelWidth: { value: '33' },
auto: { value: '{{true}}' },
fieldBorderRadius: { value: '6' },
- selectedTextColor: { value: '#1B1F24' },
- fieldBorderColor: { value: '#CCD1D5' },
- errTextColor: { value: '#D72D39' },
- fieldBackgroundColor: { value: '#fff' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
+ fieldBorderColor: { value: 'var(--cc-default-border)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
+ fieldBackgroundColor: { value: 'var(--cc-surface1-surface)' },
direction: { value: 'left' },
alignment: { value: 'side' },
padding: { value: 'default' },
@@ -350,7 +350,7 @@ export const dropdownV2Config = {
icon: { value: 'IconHome2' },
iconVisibility: { value: false },
iconColor: { value: '#6A727C' },
- accentColor: { value: '#4368E3' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/emailinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/emailinput.js
index 825340616f..25f83722ba 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/emailinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/emailinput.js
@@ -80,9 +80,9 @@ export const emailinputConfig = {
},
styles: {
color: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -132,33 +132,33 @@ export const emailinputConfig = {
},
backgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -169,9 +169,9 @@ export const emailinputConfig = {
visibility: true,
},
iconColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Icon color',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
accordian: 'field',
visibility: false,
showLabel: false,
@@ -271,17 +271,17 @@ export const emailinputConfig = {
},
events: [],
styles: {
- textColor: { value: '#1B1F24' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- errTextColor: { value: '#D72D39' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
- iconColor: { value: '#CCD1D5' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
- color: { value: '#1B1F24' },
+ color: { value: 'var(--cc-primary-text)' },
auto: { value: '{{true}}' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/filepicker.js b/frontend/src/AppBuilder/WidgetManager/widgets/filepicker.js
index 8df492daa5..0854d156cf 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/filepicker.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/filepicker.js
@@ -16,86 +16,72 @@ export const filepickerConfig = {
handle: 'clearFiles',
displayName: 'Clear Files',
},
+ {
+ handle: 'setFileName',
+ displayName: 'Set File Name',
+ },
+ {
+ handle: 'setVisibility',
+ displayName: 'Set Visibility',
+ },
+ {
+ handle: 'setLoading',
+ displayName: 'Set Loading',
+ },
+ {
+ handle: 'setDisable',
+ displayName: 'Set Disable',
+ },
],
properties: {
- instructionText: {
+ label: {
type: 'code',
- displayName: 'Instruction text',
+ displayName: 'Label',
validation: {
schema: { type: 'string' },
- defaultValue: 'Instruction text',
+ defaultValue: 'Label',
},
+ accordian: 'Data',
+ },
+ instructionText: {
+ type: 'code',
+ displayName: 'Placeholder',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: 'Drag and drop files or click here to upload',
+ },
+ accordian: 'Data',
},
enableDropzone: {
- type: 'code',
+ type: 'toggle',
displayName: 'Use drop zone',
- validation: {
- schema: { type: 'boolean' },
- defaultValue: true,
- },
- },
- enablePicker: {
- type: 'code',
- displayName: 'Use file picker',
- validation: {
- schema: { type: 'boolean' },
- defaultValue: true,
- },
- },
- enableMultiple: {
- type: 'code',
- displayName: 'Pick multiple files',
validation: {
schema: { type: 'boolean' },
defaultValue: false,
},
+ accordian: 'Data',
},
- maxFileCount: {
- type: 'code',
- displayName: 'Max file count',
+ enablePicker: {
+ type: 'toggle',
+ displayName: 'Use file picker',
validation: {
- schema: {
- type: 'union',
- schemas: [{ type: 'string' }, { type: 'number' }],
- },
- defaultValue: 2,
+ schema: { type: 'boolean' },
+ defaultValue: false,
},
+ accordian: 'Data',
},
- fileType: {
- type: 'code',
- displayName: 'Accept file types',
+ enableMultiple: {
+ type: 'toggle',
+ displayName: 'Allow picking multiple files',
validation: {
- schema: {
- type: 'string',
- },
- defaultValue: 'image/*',
- },
- },
- maxSize: {
- type: 'code',
- displayName: 'Max size limit (Bytes)',
- validation: {
- schema: {
- type: 'union',
- schemas: [{ type: 'string' }, { type: 'number' }],
- },
- defaultValue: 1048576,
- },
- },
- minSize: {
- type: 'code',
- displayName: 'Min size limit (Bytes)',
- validation: {
- schema: {
- type: 'union',
- schemas: [{ type: 'string' }, { type: 'number' }],
- },
- defaultValue: 50,
+ schema: { type: 'boolean' },
+ defaultValue: false,
},
+ accordian: 'Data',
},
parseContent: {
type: 'toggle',
- displayName: 'Parse content',
+ displayName: 'Enable parsing',
validation: {
schema: {
type: 'boolean',
@@ -122,26 +108,52 @@ export const filepickerConfig = {
defaultValue: 'auto-detect',
},
},
- },
- events: {
- onFileSelected: { displayName: 'On File Selected' },
- onFileLoaded: { displayName: 'On File Loaded' },
- onFileDeselected: { displayName: 'On File Deselected' },
- },
- styles: {
+ loadingState: {
+ type: 'toggle',
+ displayName: 'Show loading state',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ },
visibility: {
type: 'toggle',
displayName: 'Visibility',
+ section: 'additionalActions',
validation: {
- schema: {
- type: 'boolean',
- },
+ schema: { type: 'boolean' },
defaultValue: true,
},
},
disabledState: {
type: 'toggle',
displayName: 'Disable',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ },
+ tooltip: {
+ type: 'code',
+ displayName: 'Tooltip',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '',
+ },
+ },
+ },
+ events: {
+ onFileSelected: { displayName: 'On File Selected' },
+ onFileLoaded: { displayName: 'On File Loaded' },
+ onFileDeselected: { displayName: 'On File Deselected' },
+ },
+ validation: {
+ enableValidation: {
+ type: 'toggle',
+ displayName: 'Make this field mandatory',
validation: {
schema: {
type: 'boolean',
@@ -149,21 +161,120 @@ export const filepickerConfig = {
defaultValue: false,
},
},
- borderRadius: {
+ fileType: {
type: 'code',
- displayName: 'Border radius',
+ displayName: 'Accept file types',
+ validation: {
+ schema: {
+ type: 'string',
+ },
+ defaultValue: 'image/*',
+ },
+ },
+ minSize: {
+ type: 'code',
+ displayName: 'Min size limit (Bytes)',
validation: {
schema: {
type: 'union',
schemas: [{ type: 'string' }, { type: 'number' }],
},
- defaultValue: 4,
+ defaultValue: 50,
+ },
+ },
+ maxSize: {
+ type: 'code',
+ displayName: 'Max size limit (Bytes)',
+ validation: {
+ schema: {
+ type: 'union',
+ schemas: [{ type: 'string' }, { type: 'number' }],
+ },
+ defaultValue: 1048576,
+ },
+ },
+ minFileCount: {
+ type: 'code',
+ displayName: 'Min file count',
+ validation: {
+ schema: {
+ type: 'union',
+ schemas: [{ type: 'string' }, { type: 'number' }],
+ },
+ defaultValue: 2,
+ },
+ },
+ maxFileCount: {
+ type: 'code',
+ displayName: 'Max file count',
+ validation: {
+ schema: {
+ type: 'union',
+ schemas: [{ type: 'string' }, { type: 'number' }],
+ },
+ defaultValue: 2,
},
},
},
+ styles: {
+ dropzoneTitleColor: {
+ type: 'colorSwatches',
+ displayName: 'Title',
+ validation: { schema: { type: 'string' }, defaultValue: false },
+ accordian: 'File Drop Area',
+ },
+ dropzoneActiveColor: {
+ type: 'colorSwatches',
+ displayName: 'Active color',
+ validation: { schema: { type: 'string' }, defaultValue: false },
+ accordian: 'File Drop Area',
+ },
+ dropzoneErrorColor: {
+ type: 'colorSwatches',
+ displayName: 'Error color',
+ validation: { schema: { type: 'string' }, defaultValue: false },
+ accordian: 'File Drop Area',
+ },
+ containerBackgroundColor: {
+ type: 'colorSwatches',
+ displayName: 'Background',
+ validation: { schema: { type: 'string' }, defaultValue: false },
+ accordian: 'Container',
+ },
+ containerBorder: {
+ type: 'colorSwatches',
+ displayName: 'Border',
+ validation: { schema: { type: 'string' }, defaultValue: 'transparent' },
+ accordian: 'Container',
+ },
+ borderRadius: {
+ type: 'numberInput',
+ displayName: 'Border Radius',
+ validation: { schema: { type: 'number' }, defaultValue: 6 },
+ accordian: 'Container',
+ },
+ containerBoxShadow: {
+ type: 'boxShadow',
+ displayName: 'Box shadow',
+ validation: { schema: { type: 'string' }, defaultValue: '0px 1px 3px rgba(0,0,0,0.1)' },
+ accordian: 'Container',
+ },
+ containerPadding: {
+ type: 'numberInput',
+ displayName: 'Padding',
+ validation: { schema: { type: 'string' }, defaultValue: 16 },
+ accordian: 'Container',
+ },
+ },
exposedVariables: {
- file: [{ name: '', content: '', dataURL: '', type: '', parsedData: '' }],
+ file: [{ name: '', content: '', dataURL: '', type: '', parsedValue: null }],
isParsing: false,
+ isValid: true,
+ fileSize: 0,
+ isMandatory: false,
+ isLoading: false,
+ isVisible: true,
+ isDisabled: false,
},
definition: {
others: {
@@ -171,22 +282,44 @@ export const filepickerConfig = {
showOnMobile: { value: '{{false}}' },
},
properties: {
+ label: { value: 'Upload files' },
instructionText: { value: 'Drag and drop files here or click to select files' },
enableDropzone: { value: '{{true}}' },
enablePicker: { value: '{{true}}' },
- maxFileCount: { value: '{{2}}' },
enableMultiple: { value: '{{false}}' },
- fileType: { value: '{{"image/*"}}' },
- maxSize: { value: '{{1048576}}' },
- minSize: { value: '{{50}}' },
parseContent: { value: '{{false}}' },
parseFileType: { value: 'auto-detect' },
+ loadingState: { value: '{{false}}' },
+ visibility: { value: '{{true}}' },
+ disabledState: { value: '{{false}}' },
+ tooltip: { value: '' },
},
events: [],
styles: {
- visibility: { value: '{{true}}' },
- disabledState: { value: '{{false}}' },
- borderRadius: { value: '{{4}}' },
+ borderRadius: { value: '{{6}}' },
+ dropzoneTitleColor: { value: 'var(--cc-primary-text)' },
+ dropzoneActiveColor: { value: 'var(--cc-primary-brand)' },
+ dropzoneErrorColor: { value: 'var(--cc-error-systemStatus)' },
+ containerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ containerBorder: { value: 'var(--cc-default-border)' },
+ containerBoxShadow: { value: '0px 1px 3px rgba(0,0,0,0.1)' },
+ containerPadding: { value: '16px' },
+ },
+ validation: {
+ enableValidation: { value: '{{false}}' },
+ fileType: { value: '{{}}' },
+ minSize: { value: '{{50}}' },
+ maxSize: { value: '{{51200000}}' },
+ minFileCount: { value: '{{0}}' },
+ maxFileCount: { value: '{{2}}' },
+ },
+ validation: {
+ enableValidation: { value: '{{false}}' },
+ fileType: { value: '{{}}' },
+ minSize: { value: '{{50}}' },
+ maxSize: { value: '{{51200000}}' },
+ minFileCount: { value: '{{0}}' },
+ maxFileCount: { value: '{{2}}' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/form.js b/frontend/src/AppBuilder/WidgetManager/widgets/form.js
index 7c558a73e8..bd337fa2e6 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/form.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/form.js
@@ -3,7 +3,7 @@ export const formConfig = {
displayName: 'Form',
description: 'Wrapper for multiple components',
defaultSize: {
- width: 13,
+ width: 15,
height: 450,
},
defaultChildren: [
@@ -17,12 +17,13 @@ export const formConfig = {
},
properties: ['text'],
accessorKey: 'text',
- styles: ['fontWeight', 'textSize', 'textColor'],
+ styles: ['fontWeight', 'textSize', 'textColor', 'boxShadow'],
defaultValue: {
text: 'Form title',
textSize: 16,
- textColor: '#000',
+ textColor: 'var(--cc-primary-text)',
fontWeight: 'bold',
+ boxShadow: '0px 0px 0px 0px #00000090',
},
},
{
@@ -40,46 +41,6 @@ export const formConfig = {
padding: 'none',
},
},
- {
- componentName: 'TextInput',
- layout: {
- top: 20,
- left: 1,
- height: 40,
- width: 41,
- },
- properties: ['placeholder', 'label'],
- styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
- defaultValue: {
- placeholder: 'Enter your name',
- label: 'Name',
- width: '{{60}}',
- direction: 'left',
- alignment: 'side',
- auto: '{{false}}',
- padding: 'default',
- },
- },
- {
- componentName: 'NumberInput',
- layout: {
- top: 80,
- left: 1,
- height: 40,
- width: 41,
- },
- properties: ['placeholder', 'label'],
- styles: ['alignment', 'width', 'auto', 'padding', 'direction'],
- defaultValue: {
- placeholder: 'Age',
- label: 'Age',
- width: '{{60}}',
- direction: 'left',
- alignment: 'side',
- auto: '{{false}}',
- padding: 'default',
- },
- },
],
component: 'Form',
others: {
@@ -87,9 +48,11 @@ export const formConfig = {
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
properties: {
+ showHeader: { type: 'toggle', displayName: 'Header' },
+ showFooter: { type: 'toggle', displayName: 'Footer' },
buttonToSubmit: {
type: 'select',
- displayName: 'Button to submit form',
+ displayName: 'Submit button',
options: [{ name: 'None', value: 'none' }],
validation: {
schema: { type: 'string' },
@@ -100,6 +63,65 @@ export const formConfig = {
value: false,
},
},
+ generateFormFrom: {
+ type: 'dropdownMenu',
+ displayName: 'Generate form from',
+ options: [
+ { name: 'Raw JSON', value: 'rawJson' },
+ { name: 'JSON schema', value: 'jsonSchema' },
+ ],
+ section: 'data',
+ validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'object' }] } },
+ newLine: true,
+ },
+ JSONData: {
+ type: 'code',
+ displayName: '',
+ conditionallyRender: {
+ key: 'generateFormFrom',
+ value: 'rawJson',
+ },
+ section: 'data',
+ showLabel: false,
+ validation: {
+ schema: { type: 'object' },
+ },
+ },
+ newJsonSchema: {
+ type: 'code',
+ displayName: '',
+ conditionallyRender: {
+ key: 'generateFormFrom',
+ value: 'jsonSchema',
+ },
+ section: 'data',
+ showLabel: false,
+ validation: {
+ schema: { type: 'object' },
+ },
+ },
+ fields: {
+ type: 'array',
+ displayName: 'Table Columns',
+ },
+ validateOnSubmit: {
+ type: 'toggle',
+ displayName: 'Validate all fields on submission',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: true,
+ },
+ },
+ resetOnSubmit: {
+ type: 'toggle',
+ displayName: 'Reset form on submission',
+ section: 'additionalActions',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: true,
+ },
+ },
loadingState: {
type: 'toggle',
displayName: 'Loading state',
@@ -109,20 +131,29 @@ export const formConfig = {
defaultValue: false,
},
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
advanced: {
type: 'toggle',
displayName: ' Use custom schema',
+ section: 'deprecated',
},
JSONSchema: {
type: 'code',
displayName: 'JSON Schema',
+ section: 'deprecated',
conditionallyRender: {
key: 'advanced',
value: true,
},
},
- showHeader: { type: 'toggle', displayName: 'Header' },
- showFooter: { type: 'toggle', displayName: 'Footer' },
headerHeight: {
type: 'numberInput',
displayName: 'Header height',
@@ -173,19 +204,19 @@ export const formConfig = {
},
styles: {
headerBackgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Header background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
footerBackgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Footer background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
backgroundColor: {
@@ -254,25 +285,39 @@ export const formConfig = {
},
properties: {
loadingState: { value: '{{false}}' },
+ dynamicHeight: { value: '{{false}}' },
advanced: { value: '{{false}}' },
JSONSchema: {
value:
"{{ {title: 'User registration form', properties: {firstname: {type: 'textinput',value: 'Maria',label:'First name', validation:{maxLength:6}, styles: {backgroundColor: '#f6f5ff',textColor: 'black'},},lastname:{type: 'textinput',value: 'Doe', label:'Last name', styles: {backgroundColor: '#f6f5ff',textColor: 'black'},},age:{type:'number', label:'Age'},}, submitButton: {value: 'Submit', styles: {backgroundColor: '#3a433b',borderColor:'#595959'}}} }}",
},
+ newJsonSchema: {
+ value:
+ "{{ {title: 'User registration form', properties: {firstname: {type: 'textinput',value: 'Maria',label:'First name', validation:{maxLength:6}, styles: {backgroundColor: '#f6f5ff',textColor: 'black'},},lastname:{type: 'textinput',value: 'Doe', label:'Last name', styles: {backgroundColor: '#f6f5ff',textColor: 'black'},},age:{type:'number', label:'Age'},}, submitButton: {value: 'Submit', styles: {backgroundColor: '#3a433b',borderColor:'#595959'}}} }}",
+ },
showHeader: { value: '{{true}}' },
showFooter: { value: '{{true}}' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
headerHeight: { value: 60 },
footerHeight: { value: 60 },
+ validateOnSubmit: { value: '{{true}}' },
+ resetOnSubmit: { value: '{{true}}' },
+ generateFormFrom: '',
+ fields: {
+ value: [],
+ },
+ JSONData: {
+ value: undefined,
+ },
},
events: [],
styles: {
- backgroundColor: { value: '#fff' },
+ headerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ footerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
borderRadius: { value: '0' },
- borderColor: { value: '#fff' },
- headerBackgroundColor: { value: '#fff' },
- footerBackgroundColor: { value: '#fff' },
+ borderColor: { value: 'var(--cc-default-border)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/image.js b/frontend/src/AppBuilder/WidgetManager/widgets/image.js
index ca74e31d12..ead4078270 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/image.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/image.js
@@ -157,7 +157,7 @@ export const imageConfig = {
displayName: 'Background',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
accordian: 'Container',
},
@@ -258,7 +258,7 @@ export const imageConfig = {
styles: {
imageFit: { value: 'contain' },
imageShape: { value: 'none' },
- backgroundColor: { value: '#FFFFFF' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
borderColor: { value: '' },
borderRadius: { value: '{{6}}' },
boxShadow: { value: '0px 0px 0px 0px #00000090' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/kanban.js b/frontend/src/AppBuilder/WidgetManager/widgets/kanban.js
index cd39d0bd7b..f86b76d881 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/kanban.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/kanban.js
@@ -22,7 +22,7 @@ export const kanbanConfig = {
text: '{{cardData.title}}',
fontWeight: 'bold',
textSize: 16,
- textColor: '#000',
+ textColor: 'var(--cc-primary-text)',
},
},
{
@@ -38,7 +38,7 @@ export const kanbanConfig = {
defaultValue: {
text: '{{cardData.description}}',
textSize: 14,
- textColor: '#000',
+ textColor: 'var(--cc-primary-text)',
},
},
],
@@ -157,7 +157,7 @@ export const kanbanConfig = {
styles: {
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
- accentColor: { value: 'var(--primary-brand)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/link.js b/frontend/src/AppBuilder/WidgetManager/widgets/link.js
index 16d5f13368..ba50ae50a4 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/link.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/link.js
@@ -78,7 +78,7 @@ export const linkConfig = {
displayName: 'Text color',
validation: {
schema: { type: 'string' },
- defaultValue: '#375FCF',
+ defaultValue: 'var(--cc-primary-brand)',
},
accordian: 'Link text',
},
@@ -216,7 +216,7 @@ export const linkConfig = {
},
events: [],
styles: {
- textColor: { value: '#4368E3' },
+ textColor: { value: 'var(--cc-primary-brand)' },
textSize: { value: '{{14}}' },
underline: { value: 'on-hover' },
verticalAlignment: { value: 'center' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/listview.js b/frontend/src/AppBuilder/WidgetManager/widgets/listview.js
index 6c599bc2fc..4ca2bd0e52 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/listview.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/listview.js
@@ -13,7 +13,7 @@ export const listviewConfig = {
top: 15,
left: 3,
height: 100,
- width: 7,
+ width: 4,
},
properties: ['source'],
accessorKey: 'imageURL',
@@ -24,6 +24,7 @@ export const listviewConfig = {
top: 50,
left: 11,
height: 30,
+ width: 4,
},
properties: ['text'],
accessorKey: 'text',
@@ -49,15 +50,26 @@ export const listviewConfig = {
data: {
type: 'code',
displayName: 'List data',
- schema: {
- type: 'union',
- schemas: [
- { type: 'array', element: { type: 'object' } },
- { type: 'array', element: { type: 'string' } },
- ],
+ validation: {
+ schema: {
+ type: 'union',
+ schemas: [
+ { type: 'array', element: { type: 'object' } },
+ { type: 'array', element: { type: 'string' } },
+ ],
+ },
defaultValue: "[{text: 'Sample text 1'}]",
},
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
mode: {
type: 'select',
displayName: 'Mode',
@@ -129,15 +141,15 @@ export const listviewConfig = {
displayName: 'Background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#fff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
borderColor: {
type: 'colorSwatches',
- displayName: 'Border color',
+ displayName: 'Border',
validation: {
schema: { type: 'string' },
- defaultValue: '#dadcde',
+ defaultValue: 'var(--cc-default-border)',
},
},
visibility: {
@@ -186,6 +198,7 @@ export const listviewConfig = {
rowHeight: {
value: '100',
},
+ dynamicHeight: { value: '{{false}}' },
visible: { value: '{{true}}' },
showBorder: { value: '{{true}}' },
rowsPerPage: { value: '{{10}}' },
@@ -193,8 +206,8 @@ export const listviewConfig = {
},
events: [],
styles: {
- backgroundColor: { value: '#fff' },
- borderColor: { value: '#dadcde' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ borderColor: { value: 'var(--cc-default-border)' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
borderRadius: { value: '{{4}}' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/modal.js b/frontend/src/AppBuilder/WidgetManager/widgets/modal.js
index 3443c73c9b..90182b6494 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/modal.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/modal.js
@@ -85,7 +85,7 @@ export const modalConfig = {
displayName: 'Header background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
headerTextColor: {
@@ -93,7 +93,7 @@ export const modalConfig = {
displayName: 'Header title color',
validation: {
schema: { type: 'string' },
- defaultValue: '#000000',
+ defaultValue: 'var(--cc-primary-text)',
},
},
bodyBackgroundColor: {
@@ -101,7 +101,7 @@ export const modalConfig = {
displayName: 'Body background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
disabledState: {
@@ -170,12 +170,12 @@ export const modalConfig = {
},
events: [],
styles: {
- headerBackgroundColor: { value: '#ffffffff' },
- headerTextColor: { value: '#000000' },
- bodyBackgroundColor: { value: '#ffffffff' },
+ headerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ headerTextColor: { value: 'var(--cc-primary-text)' },
+ bodyBackgroundColor: { value: 'var(--cc-surface1-surface)' },
disabledState: { value: '{{false}}' },
visibility: { value: '{{true}}' },
- triggerButtonBackgroundColor: { value: 'var(--primary-brand)' },
+ triggerButtonBackgroundColor: { value: 'var(--cc-primary-brand)' },
triggerButtonTextColor: { value: '#ffffffff' },
},
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/modalV2.js b/frontend/src/AppBuilder/WidgetManager/widgets/modalV2.js
index a3c89acf93..a9c95ce2e4 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/modalV2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/modalV2.js
@@ -92,18 +92,6 @@ export const modalV2Config = {
accordian: 'Data',
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 400 },
},
- headerHeight: {
- type: 'numberInput',
- displayName: 'Header height',
- accordian: 'Data',
- validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 80 },
- },
- footerHeight: {
- type: 'numberInput',
- displayName: 'Footer height',
- accordian: 'Data',
- validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 80 },
- },
hideOnEsc: { type: 'toggle', displayName: 'Close on escape key', section: 'additionalActions' },
closeOnClickingOutside: { type: 'toggle', displayName: 'Close on clicking outside', section: 'additionalActions' },
hideCloseButton: { type: 'toggle', displayName: 'Hide close button', section: 'additionalActions' },
@@ -128,7 +116,7 @@ export const modalV2Config = {
defaultValue: {
text: 'Modal title',
textSize: 20,
- textColor: '#000',
+ textColor: 'var(--cc-primary-text)',
},
},
{
@@ -141,11 +129,30 @@ export const modalV2Config = {
},
displayName: 'ModalFooterCancel',
properties: ['text'],
- styles: ['type', 'borderColor', 'padding'],
+ styles: [
+ 'textColor',
+ 'loaderColor',
+ 'iconColor',
+ 'borderRadius',
+ 'iconVisibility',
+ 'direction',
+ 'icon',
+ 'type',
+ 'borderColor',
+ 'padding',
+ ],
defaultValue: {
+ textColor: '#000000',
+ loaderColor: 'var(--cc-surface1-surface)',
+ icon: 'IconAlignBoxBottomLeft',
text: 'Button1',
type: 'outline',
borderColor: '#CCD1D5',
+ iconColor: 'var(--cc-default-icon)',
+ borderRadius: 6,
+ iconVisibility: false,
+ direction: 'left',
+ padding: 'default',
},
},
{
@@ -166,31 +173,31 @@ export const modalV2Config = {
],
styles: {
headerBackgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Header background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
footerBackgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Footer background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
bodyBackgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Body background color',
validation: {
schema: { type: 'string' },
- defaultValue: '#ffffffff',
+ defaultValue: 'var(--cc-surface1-surface)',
},
},
triggerButtonBackgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Trigger button background color',
validation: {
schema: { type: 'string' },
@@ -198,7 +205,7 @@ export const modalV2Config = {
},
},
triggerButtonTextColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Trigger button text color',
validation: {
schema: { type: 'string' },
@@ -267,10 +274,10 @@ export const modalV2Config = {
},
events: [],
styles: {
- headerBackgroundColor: { value: '#ffffffff' },
- footerBackgroundColor: { value: '#ffffffff' },
- bodyBackgroundColor: { value: '#ffffffff' },
- triggerButtonBackgroundColor: { value: '#4D72FA' },
+ headerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ footerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ bodyBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ triggerButtonBackgroundColor: { value: 'var(--cc-primary-brand)' },
triggerButtonTextColor: { value: '#ffffffff' },
},
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/multiselectV2.js b/frontend/src/AppBuilder/WidgetManager/widgets/multiselectV2.js
index c9d89045aa..161f7bba83 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/multiselectV2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/multiselectV2.js
@@ -197,7 +197,7 @@ export const multiselectV2Config = {
labelColor: {
type: 'colorSwatches',
displayName: 'Color',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -250,32 +250,32 @@ export const multiselectV2Config = {
fieldBackgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
fieldBorderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
selectedTextColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error Text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -384,14 +384,14 @@ export const multiselectV2Config = {
},
events: [],
styles: {
- labelColor: { value: '#1B1F24' },
+ labelColor: { value: 'var(--cc-primary-text)' },
labelWidth: { value: '33' },
auto: { value: '{{true}}' },
fieldBorderRadius: { value: '6' },
- selectedTextColor: { value: '#1B1F24' },
- fieldBorderColor: { value: '#CCD1D5' },
- errTextColor: { value: '#D72D39' },
- fieldBackgroundColor: { value: '#fff' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
+ fieldBorderColor: { value: 'var(--cc-default-border)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
+ fieldBackgroundColor: { value: 'var(--cc-surface1-surface)' },
direction: { value: 'left' },
alignment: { value: 'side' },
padding: { value: 'default' },
@@ -399,7 +399,7 @@ export const multiselectV2Config = {
icon: { value: 'IconHome2' },
iconVisibility: { value: false },
iconColor: { value: '#6A727C' },
- accentColor: { value: 'var(--primary-brand)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js
index cba9c04cd1..261fad96e8 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js
@@ -74,7 +74,7 @@ export const numberinputConfig = {
color: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -126,31 +126,31 @@ export const numberinputConfig = {
backgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: 'var(--primary-brand)' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -163,7 +163,7 @@ export const numberinputConfig = {
iconColor: {
type: 'colorSwatches',
displayName: 'Icon color',
- validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
accordian: 'field',
visibility: false,
showLabel: false,
@@ -277,13 +277,13 @@ export const numberinputConfig = {
events: [],
styles: {
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: 'var(--primary-brand)' },
- errTextColor: { value: '#D72D39' },
- textColor: { value: '#1B1F24' },
- color: { value: '#1B1F24' },
- iconColor: { value: '#CFD3D859' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ color: { value: 'var(--cc-primary-text)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/passwordinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/passwordinput.js
index fad0d00735..839bb01732 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/passwordinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/passwordinput.js
@@ -86,7 +86,7 @@ export const passinputConfig = {
color: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -138,31 +138,31 @@ export const passinputConfig = {
backgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
- accordian: 'field',
- },
- accentColor: {
- type: 'colorSwatches',
- displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: 'var(--primary-brand)' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
+ accordian: 'field',
+ },
+ accentColor: {
+ type: 'colorSwatches',
+ displayName: 'Accent',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -175,7 +175,7 @@ export const passinputConfig = {
iconColor: {
type: 'colorSwatches',
displayName: 'Icon color',
- validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
accordian: 'field',
visibility: false,
showLabel: false,
@@ -276,16 +276,16 @@ export const passinputConfig = {
events: [],
styles: {
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: 'var(--primary-brand)' },
- errTextColor: { value: '#D72D39' },
- textColor: { value: '#1B1F24' },
- iconColor: { value: '#CFD3D859' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
- color: { value: '#1B1F24' },
+ color: { value: 'var(--cc-primary-text)' },
auto: { value: '{{true}}' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/phoneinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/phoneinput.js
index 83e35ffc68..617d72738f 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/phoneinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/phoneinput.js
@@ -85,9 +85,9 @@ export const phoneinputConfig = {
},
styles: {
color: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -137,33 +137,33 @@ export const phoneinputConfig = {
},
backgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
borderRadius: {
@@ -270,16 +270,16 @@ export const phoneinputConfig = {
},
events: [],
styles: {
- textColor: { value: '#1B1F24' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- errTextColor: { value: '#D72D39' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
- color: { value: '#1B1F24' },
+ color: { value: 'var(--cc-primary-text)' },
auto: { value: '{{true}}' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/radioButtonV2.js b/frontend/src/AppBuilder/WidgetManager/widgets/radioButtonV2.js
index 62a084d75a..3ae1fb5e65 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/radioButtonV2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/radioButtonV2.js
@@ -279,16 +279,16 @@ export const radiobuttonV2Config = {
},
events: [],
styles: {
- labelColor: { value: '#11181C' },
+ labelColor: { value: 'var(--cc-primary-text)' },
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' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ switchOffBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ switchOnBackgroundColor: { value: 'var(--cc-primary-brand)' },
+ handleColor: { value: 'var(--cc-surface1-surface)' },
+ optionsTextColor: { value: 'var(--cc-primary-text)' },
padding: { value: 'default' },
},
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/radiobutton.js b/frontend/src/AppBuilder/WidgetManager/widgets/radiobutton.js
index 66d055ca5e..cb8f086b19 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/radiobutton.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/radiobutton.js
@@ -57,7 +57,7 @@ export const radiobuttonConfig = {
displayName: 'Text color',
validation: {
schema: { type: 'string' },
- defaultValue: '#000000',
+ defaultValue: 'var(--cc-primary-text)',
},
},
activeColor: {
@@ -65,7 +65,7 @@ export const radiobuttonConfig = {
displayName: 'Active color',
validation: {
schema: { type: 'string' },
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-primary-brand)',
},
},
visibility: {
@@ -112,8 +112,8 @@ export const radiobuttonConfig = {
},
events: [],
styles: {
- textColor: { value: '' },
- activeColor: { value: 'var(--primary-brand)' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ activeColor: { value: 'var(--cc-primary-brand)' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/rangeslider.js b/frontend/src/AppBuilder/WidgetManager/widgets/rangeslider.js
index 186ae7fbc7..00531a9a90 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/rangeslider.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/rangeslider.js
@@ -12,9 +12,25 @@ export const rangeSliderConfig = {
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
properties: {
+ enableTwoHandle: {
+ type: 'switch',
+ displayName: 'Slider type',
+ options: [
+ { displayName: 'Slider', value: 'slider' },
+ { displayName: 'Range slider', value: 'rangeSlider' },
+ ],
+ isFxNotRequired: true,
+ defaultValue: { value: 'slider' },
+ fullWidth: true,
+ },
+ label: {
+ type: 'code',
+ displayName: 'Label',
+ validation: { schema: { type: 'string' }, defaultValue: 'Label' },
+ },
min: {
type: 'number',
- displayName: 'Min',
+ displayName: 'Min value',
validation: {
schema: { type: 'number' },
defaultValue: 0,
@@ -22,67 +38,216 @@ export const rangeSliderConfig = {
},
max: {
type: 'number',
- displayName: 'Max',
+ displayName: 'Max value',
validation: {
schema: { type: 'number' },
defaultValue: 100,
},
},
value: {
- type: 'code',
- displayName: 'Value',
+ type: 'number',
+ displayName: 'Default value',
+ conditionallyRender: {
+ key: 'enableTwoHandle',
+ value: 'slider',
+ },
+
validation: {
schema: {
- type: 'union',
- schemas: [{ type: 'array', element: { type: 'number' } }, { type: 'number' }],
+ schema: { type: 'number' },
+ defaultValue: 50,
},
- defaultValue: 50,
},
},
- enableTwoHandle: {
+ startValue: {
+ type: 'number',
+ displayName: 'Default start value',
+ conditionallyRender: {
+ key: 'enableTwoHandle',
+ value: 'rangeSlider',
+ },
+
+ validation: {
+ schema: {
+ schema: { type: 'number' },
+ defaultValue: 50,
+ },
+ },
+ },
+ endValue: {
+ type: 'number',
+ displayName: 'Default end value',
+ conditionallyRender: {
+ key: 'enableTwoHandle',
+ value: 'rangeSlider',
+ },
+
+ validation: {
+ schema: {
+ schema: { type: 'number' },
+ defaultValue: 80,
+ },
+ },
+ },
+ stepSize: {
+ type: 'number',
+ displayName: 'Step size',
+ validation: {
+ schema: { type: 'number' },
+ defaultValue: 1,
+ },
+ },
+ schema: {
+ type: 'code',
+ displayName: 'Set marks',
+ },
+ loadingState: {
type: 'toggle',
- displayName: 'Two handles',
+ displayName: 'Show loading state',
validation: {
schema: { type: 'boolean' },
defaultValue: false,
},
+ 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: false,
+ },
+ section: 'additionalActions',
+ },
+ tooltip: {
+ type: 'code',
+ displayName: 'Tooltip',
+ validation: { schema: { type: 'string' }, defaultValue: 'Tooltip text' },
+ section: 'additionalActions',
+ placeholder: 'Enter tooltip text',
},
},
events: {
onChange: { displayName: 'On change' },
},
styles: {
+ color: {
+ type: 'colorSwatches',
+ 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: '',
+ 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',
+ isFxNotRequired: true,
+ },
+ width: {
+ type: 'slider',
+ displayName: 'Width',
+ accordian: 'label',
+ conditionallyRender: {
+ key: 'alignment',
+ value: 'side',
+ },
+ isFxNotRequired: true,
+ },
+ auto: {
+ type: 'checkbox',
+ displayName: 'auto',
+ showLabel: false,
+ validation: { schema: { type: 'boolean' }, defaultValue: true },
+ accordian: 'label',
+ conditionallyRender: {
+ key: 'alignment',
+ value: 'side',
+ },
+ isFxNotRequired: true,
+ },
lineColor: {
type: 'colorSwatches',
- displayName: 'Line color',
+ displayName: 'Track',
validation: {
schema: { type: 'string' },
- defaultValue: '#375FCF',
- },
- },
- handleColor: {
- type: 'colorSwatches',
- displayName: 'Handle color',
- validation: {
- schema: { type: 'string' },
- defaultValue: '#375FCF',
+ defaultValue: '#E4E7EB',
},
+ accordian: 'slider',
},
trackColor: {
type: 'colorSwatches',
- displayName: 'Track color',
+ displayName: 'Accent',
validation: {
schema: { type: 'string' },
- defaultValue: '#375FCF',
},
+ accordian: 'slider',
},
- visibility: {
- type: 'code',
- displayName: 'Visibility',
+ handleColor: {
+ type: 'colorSwatches',
+ displayName: 'Handle',
validation: {
- schema: { type: 'boolean' },
- defaultValue: true,
+ schema: { type: 'string' },
+ defaultValue: '#FFFFFF',
},
+ accordian: 'slider',
+ },
+ handleBorderColor: {
+ type: 'colorSwatches',
+ displayName: 'Handle border',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#ACB2B9',
+ },
+ accordian: 'slider',
+ },
+ markerLabel: {
+ type: 'colorSwatches',
+ displayName: 'Marker label',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#1B1F24',
+ },
+ accordian: 'slider',
+ },
+ 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',
},
padding: {
type: 'switch',
@@ -100,13 +265,52 @@ export const rangeSliderConfig = {
},
exposedVariables: {
value: null,
+ label: 'Label',
+ isVisible: true,
+ isDisabled: false,
+ isLoading: false,
},
+ actions: [
+ {
+ handle: 'setValue',
+ displayName: 'Set value',
+ params: [{ handle: 'num1', displayName: 'Value', defaultValue: 'New value' }],
+ },
+ {
+ handle: 'setRangeValue',
+ displayName: 'Set range value',
+ params: [
+ { handle: 'num1', displayName: 'Min value' },
+ { handle: 'num2', displayName: 'Max value' },
+ ],
+ },
+ {
+ handle: 'reset',
+ displayName: 'Reset',
+ },
+ {
+ handle: 'setDisable',
+ displayName: 'Set disable',
+ params: [{ displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setLoading',
+ displayName: 'Set loading',
+ params: [{ displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
+ },
+ {
+ handle: 'setVisibility',
+ displayName: 'Set visibility',
+ params: [{ displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
+ },
+ ],
definition: {
others: {
showOnDesktop: { value: true },
showOnMobile: { value: false },
},
properties: {
+ label: { value: 'Label' },
min: {
value: '{{0}}',
},
@@ -116,13 +320,37 @@ export const rangeSliderConfig = {
value: {
value: '{{50}}',
},
- enableTwoHandle: { value: false },
+ startValue: {
+ value: '{{50}}',
+ },
+ endValue: {
+ value: '{{80}}',
+ },
+ enableTwoHandle: { value: 'slider' },
+ stepSize: {
+ value: '{{1}}',
+ },
+ schema: {
+ value: "{{[\t{label: '25%',value: 25},{label: '50%',value: 50},{label: '75%',value: 75}\t]}}",
+ },
+ visibility: { value: '{{true}}' },
+ disabledState: { value: '{{false}}' },
+ loadingState: { value: '{{false}}' },
+ tooltip: { value: '' },
},
events: [],
styles: {
- lineColor: { value: '' },
- handleColor: { value: '' },
- trackColor: { value: 'var(--primary-brand)' },
+ lineColor: { value: 'var(--cc-surface3-surface)' },
+ handleColor: { value: 'var(--cc-surface1-surface)' },
+ handleBorderColor: { value: 'var(--cc-default-border)' },
+ trackColor: { value: 'var(--cc-primary-brand)' },
+ markerLabel: { value: 'var(--cc-primary-text)' },
+ direction: { value: 'left' },
+ width: { value: '{{33}}' },
+ alignment: { value: 'side' },
+ color: { value: 'var(--cc-primary-text)' },
+ auto: { value: '{{true}}' },
+ padding: { value: 'default' },
visibility: { value: '{{true}}' },
padding: { value: 'default' },
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js b/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js
index c964d53d6b..8580f2b56a 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js
@@ -37,6 +37,15 @@ export const richtextareaConfig = {
},
section: 'additionalActions',
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
},
events: {},
styles: {
@@ -95,6 +104,7 @@ export const richtextareaConfig = {
placeholder: { value: 'Placeholder text' },
defaultValue: { value: '' },
loadingState: { value: `{{false}}` },
+ dynamicHeight: { value: '{{false}}' },
},
events: [],
styles: {
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/spinner.js b/frontend/src/AppBuilder/WidgetManager/widgets/spinner.js
index c38bfdc468..c2e91199f0 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/spinner.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/spinner.js
@@ -27,7 +27,7 @@ export const spinnerConfig = {
displayName: 'Colour',
validation: {
schema: { type: 'string' },
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-primary-brand)',
},
},
size: {
@@ -54,7 +54,7 @@ export const spinnerConfig = {
styles: {
visibility: { value: '{{true}}' },
size: { value: 'sm' },
- colour: { value: 'var(--primary-brand)' },
+ colour: { value: 'var(--cc-primary-brand)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/starrating.js b/frontend/src/AppBuilder/WidgetManager/widgets/starrating.js
index fd2dce59d9..333feba8bc 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/starrating.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/starrating.js
@@ -70,7 +70,7 @@ export const starratingConfig = {
displayName: 'Label color',
validation: {
schema: { type: 'string' },
- defaultValue: '#000000',
+ defaultValue: 'var(--cc-primary-text)',
},
},
visibility: {
@@ -122,7 +122,7 @@ export const starratingConfig = {
events: [],
styles: {
textColor: { value: '#ffb400' },
- labelColor: { value: '' },
+ labelColor: { value: 'var(--cc-primary-text)' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
padding: { value: 'default' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/statistics.js b/frontend/src/AppBuilder/WidgetManager/widgets/statistics.js
index ecf1f70aed..dbe58f7cfe 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/statistics.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/statistics.js
@@ -57,22 +57,22 @@ export const statisticsConfig = {
primaryLabelColour: {
type: 'colorSwatches',
displayName: 'Primary label colour',
- validation: { schema: { type: 'string' }, defaultValue: '#8092AB' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
},
primaryTextColour: {
type: 'colorSwatches',
displayName: 'Primary text colour',
- validation: { schema: { type: 'string' }, defaultValue: '#000000' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
},
secondaryLabelColour: {
type: 'colorSwatches',
displayName: 'Secondary label colour',
- validation: { schema: { type: 'string' }, defaultValue: '#8092AB' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-placeholder-text)' },
},
secondaryTextColour: {
type: 'colorSwatches',
displayName: 'Secondary text colour',
- validation: { schema: { type: 'string' }, defaultValue: '#36AF8B' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-success-systemStatus)' },
},
visibility: {
type: 'toggle',
@@ -95,10 +95,10 @@ export const statisticsConfig = {
},
events: [],
styles: {
- primaryLabelColour: { value: '#8092AB' },
- primaryTextColour: { value: '#000000' },
- secondaryLabelColour: { value: '#8092AB' },
- secondaryTextColour: { value: '#36AF8B' },
+ primaryLabelColour: { value: 'var(--cc-primary-text)' },
+ primaryTextColour: { value: 'var(--cc-primary-text)' },
+ secondaryLabelColour: { value: 'var(--cc-placeholder-text)' },
+ secondaryTextColour: { value: 'var(--cc-success-systemStatus)' },
visibility: { value: '{{true}}' },
},
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/steps.js b/frontend/src/AppBuilder/WidgetManager/widgets/steps.js
index 9e71a89f90..a87311a7e2 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/steps.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/steps.js
@@ -74,7 +74,6 @@ export const stepsConfig = {
defaultValue: 1,
},
},
-
},
defaultSize: {
width: 22,
@@ -170,7 +169,7 @@ export const stepsConfig = {
displayName: 'Completed accent',
validation: {
schema: { type: 'string' },
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-primary-brand)',
},
accordian: 'steps',
},
@@ -240,11 +239,11 @@ export const stepsConfig = {
// color: { value: '' },
// textColor: { value: '' },
padding: { value: 'default' },
- incompletedAccent: { value: '#E4E7EB' },
- incompletedLabel: { value: '#1B1F24' },
- completedAccent: { value: 'var(--primary-brand)' },
- completedLabel: { value: '#1B1F24' },
- currentStepLabel: { value: '#1B1F24' },
+ incompletedAccent: { value: 'var(--cc-surface3-surface)' },
+ incompletedLabel: { value: 'var(--cc-primary-text)' },
+ completedAccent: { value: 'var(--cc-primary-brand)' },
+ completedLabel: { value: 'var(--cc-primary-text)' },
+ currentStepLabel: { value: 'var(--cc-primary-text)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/table.js b/frontend/src/AppBuilder/WidgetManager/widgets/table.js
index 9f0c4fd723..7e7d0a7610 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/table.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/table.js
@@ -269,13 +269,22 @@ export const tableConfig = {
schema: { type: 'boolean' },
},
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
},
others: {
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop ' },
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
defaultSize: {
- width: 35,
+ width: 25,
height: 456,
},
events: {
@@ -292,22 +301,19 @@ export const tableConfig = {
onTableDataDownload: { displayName: 'Download data' },
},
styles: {
- textColor: {
+ columnTitleColor: {
type: 'colorSwatches',
- displayName: 'Text Color',
- validation: {
- schema: { type: 'string' },
- defaultValue: '#000',
- },
- accordian: 'Data',
+ displayName: 'Column title',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-placeholder-text)' },
+ accordian: 'Column Header',
},
columnHeaderWrap: {
type: 'switch',
- displayName: 'Column header',
+ displayName: 'Overflow',
validation: { schema: { type: 'string' } },
- accordian: 'Data',
+ accordian: 'Column Header',
options: [
- { displayName: 'Fixed', value: 'fixed' },
+ { displayName: 'None', value: 'fixed' },
{ displayName: 'Wrap', value: 'wrap' },
],
},
@@ -315,12 +321,27 @@ export const tableConfig = {
type: 'switch',
displayName: 'Header casing',
validation: { schema: { type: 'string' } },
- accordian: 'Data',
+ accordian: 'Column Header',
options: [
- { displayName: 'AA', value: 'uppercase' },
{ displayName: 'As typed', value: 'none' },
+ { displayName: 'AA', value: 'uppercase' },
],
},
+ columnBackgroundColor: {
+ type: 'colorSwatches',
+ displayName: 'Background',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface2-surface)' },
+ accordian: 'Column Header',
+ },
+ textColor: {
+ type: 'colorSwatches',
+ displayName: 'Text',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: 'var(--cc-primary-text)',
+ },
+ accordian: 'Data',
+ },
tableType: {
type: 'select',
displayName: 'Row style',
@@ -373,6 +394,7 @@ export const tableConfig = {
},
maxRowHeightValue: {
type: 'tableRowHeightInput',
+ isFxNotRequired: true,
showLabel: false,
validation: {
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
@@ -391,11 +413,17 @@ export const tableConfig = {
},
actionButtonRadius: {
type: 'numberInput',
- displayName: 'Button radius',
+ displayName: 'Action button radius',
validation: {
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'boolean' }] },
},
- accordian: 'Action button',
+ accordian: 'Data',
+ },
+ containerBackgroundColor: {
+ type: 'colorSwatches',
+ displayName: 'Background',
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
+ accordian: 'Container',
},
borderRadius: {
type: 'numberInput',
@@ -516,7 +544,7 @@ export const tableConfig = {
loadingState: { value: '{{false}}' },
data: {
value:
- "{{ [ \n\t\t{ id: 1, name: 'Olivia Nguyen', email: 'olivia.nguyen@example.com', date: '15/05/2022', mobile_number: 9876543210, interest: ['Reading', 'Traveling','Photography'], photo: 'https://reqres.in/img/faces/7-image.jpg' }, \n\t\t{ id: 2, name: 'Liam Patel', email: 'liam.patel@example.com', date: '20/09/2021', mobile_number: 8765432109, interest: ['Cooking','Gardening','Hiking'], photo: 'https://reqres.in/img/faces/5-image.jpg' }, \n\t\t{ id: 3, name: 'Sophia Reyes', email: 'sophia.reyes@example.com', date: '01/01/2023', mobile_number: 7654321098, interest: ['Music','Dancing','Crafting'], photo: 'https://reqres.in/img/faces/3-image.jpg' }, \n\t\t{ id: 4, name: 'Jacob Hernandez', email: 'jacob.hernandez@example.com', date: '10/11/2022', mobile_number: 6543210987, interest: ['Reading', 'Traveling', 'Volunteering'], photo: 'https://reqres.in/img/faces/1-image.jpg' }, \n\t\t{ id: 5, name: 'William Sanchez', email: 'william.sanchez@example.com', date: '07/01/2021', mobile_number: 4321098765, interest: ['Music', 'Dancing', 'Hiking'], photo: 'https://reqres.in/img/faces/4-image.jpg' }, \n\t\t{ id: 6, name: 'Ethan Morales', email: 'ethan.morales@example.com', date: '05/11/2021', mobile_number: 2109876543, interest: ['Cooking', 'Traveling', 'Photography'], photo: 'https://reqres.in/img/faces/6-image.jpg' }, \n\t\t{ id: 7, name: 'Mia Tiana', email: 'mia.tiana@example.com', date: '21/11/2022', mobile_number: 1098705217, interest: ['Music', 'Gardening', 'Hiking'], photo: 'https://reqres.in/img/faces/2-image.jpg' }, \n\t\t{ id: 8, name: 'Lucas Ramirez', email: 'lucas.ramirez@example.com', date: '31/03/2023', mobile_number: 9876543210, interest: ['Reading', 'Dancing', 'Crafting'], photo: 'https://reqres.in/img/faces/9-image.jpg' }, \n\t\t{ id: 9, name: 'Alexander Vela', email: 'alexander.vela@example.com', date: '07/09/2022', mobile_number: 7654321098, interest: ['Music','Gardening','Photography'], photo: 'https://reqres.in/img/faces/8-image.jpg' }, \n\t\t{ id: 10, name: 'Michael Reyes', email: 'michael.reyes@example.com', date: '25/12/2021', mobile_number: 5432109876, interest: ['Cooking','Crafting','Volunteering'], photo: 'https://reqres.in/img/faces/10-image.jpg' } \n] }}",
+ "{{ [ \n\t\t{ id: 1, name: 'Olivia Nguyen', email: 'olivia.nguyen@example.com', date: '15/05/2022', phone: 9876543210, interest: ['Reading', 'Traveling','Photography'], photo: 'https://reqres.in/img/faces/7-image.jpg' }, \n\t\t{ id: 2, name: 'Liam Patel', email: 'liam.patel@example.com', date: '20/09/2021', phone: 8765432109, interest: ['Cooking','Gardening','Hiking'], photo: 'https://reqres.in/img/faces/5-image.jpg' }, \n\t\t{ id: 3, name: 'Sophia Reyes', email: 'sophia.reyes@example.com', date: '01/01/2023', phone: 7654321098, interest: ['Music','Dancing','Crafting'], photo: 'https://reqres.in/img/faces/3-image.jpg' }, \n\t\t{ id: 4, name: 'Jacob Hernandez', email: 'jacob.hernandez@example.com', date: '10/11/2022', phone: 6543210987, interest: ['Reading', 'Traveling', 'Volunteering'], photo: 'https://reqres.in/img/faces/1-image.jpg' }, \n\t\t{ id: 5, name: 'William Sanchez', email: 'william.sanchez@example.com', date: '07/01/2021', phone: 4321098765, interest: ['Music', 'Dancing', 'Hiking'], photo: 'https://reqres.in/img/faces/4-image.jpg' }, \n\t\t{ id: 6, name: 'Ethan Morales', email: 'ethan.morales@example.com', date: '05/11/2021', phone: 2109876543, interest: ['Cooking', 'Traveling', 'Photography'], photo: 'https://reqres.in/img/faces/6-image.jpg' }, \n\t\t{ id: 7, name: 'Mia Tiana', email: 'mia.tiana@example.com', date: '21/11/2022', phone: 1098705217, interest: ['Music', 'Gardening', 'Hiking'], photo: 'https://reqres.in/img/faces/2-image.jpg' }, \n\t\t{ id: 8, name: 'Lucas Ramirez', email: 'lucas.ramirez@example.com', date: '31/03/2023', phone: 9876543210, interest: ['Reading', 'Dancing', 'Crafting'], photo: 'https://reqres.in/img/faces/9-image.jpg' }, \n\t\t{ id: 9, name: 'Alexander Vela', email: 'alexander.vela@example.com', date: '07/09/2022', phone: 7654321098, interest: ['Music','Gardening','Photography'], photo: 'https://reqres.in/img/faces/8-image.jpg' }, \n\t\t{ id: 10, name: 'Michael Reyes', email: 'michael.reyes@example.com', date: '25/12/2021', phone: 5432109876, interest: ['Cooking','Crafting','Volunteering'], photo: 'https://reqres.in/img/faces/10-image.jpg' } \n] }}",
},
useDynamicColumn: { value: '{{false}}' },
columnData: {
@@ -663,15 +691,20 @@ export const tableConfig = {
allowSelection: { value: '{{true}}' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
+ dynamicHeight: { value: `{{false}}` },
},
events: [],
styles: {
- textColor: { value: '#000' },
+ columnTitleColor: { value: 'var(--cc-placeholder-text)' },
+ columnBackgroundColor: { value: 'var(--cc-surface2-surface)' },
+ containerBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ textColor: { value: 'var(--cc-primary-text)' },
columnHeaderWrap: { value: 'fixed' },
headerCasing: { value: 'uppercase' },
actionButtonRadius: { value: '0' },
cellSize: { value: 'regular' },
- borderRadius: { value: '8' },
+ borderRadius: { value: '6' },
+ borderColor: { value: 'var(--cc-default-border)' },
tableType: { value: 'table-classic' },
maxRowHeight: { value: 'auto' },
maxRowHeightValue: { value: '{{0}}' }, // Setting it here as 0 since TableRowHeightInput component will set the value
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/tabs.js b/frontend/src/AppBuilder/WidgetManager/widgets/tabs.js
index a9c10bebaf..70754e85d9 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/tabs.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/tabs.js
@@ -6,52 +6,47 @@ export const tabsConfig = {
width: 30,
height: 300,
},
- defaultChildren: [
- {
- componentName: 'Image',
- layout: {
- top: 60,
- left: 17,
- height: 100,
- width: 7,
- },
- tab: 0,
- properties: ['source'],
- defaultValue: {
- source: 'https://uploads-ssl.webflow.com/6266634263b9179f76b2236e/62666392f32677b5cb2fb84b_logo.svg',
- },
- },
- {
- componentName: 'Text',
- layout: {
- top: 100,
- left: 5,
- height: 50,
- width: 34,
- },
- tab: 1,
- properties: ['text'],
- defaultValue: {
- text: 'Open-source low-code framework to build & deploy internal tools within minutes.',
- },
- },
- {
- componentName: 'Table',
- layout: {
- top: 0,
- left: 1,
- width: 41,
- height: 250,
- },
- tab: 2,
- },
- ],
component: 'Tabs',
others: {
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
properties: {
+ useDynamicOptions: {
+ type: 'toggle',
+ displayName: 'Dynamic options',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ },
+ 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,
+ },
+ },
tabs: {
type: 'code',
displayName: 'Tabs',
@@ -89,6 +84,7 @@ export const tabsConfig = {
hideTabs: {
type: 'toggle',
displayName: 'Hide tabs',
+ section: 'additionalActions',
validation: {
schema: {
type: 'boolean',
@@ -99,6 +95,7 @@ export const tabsConfig = {
renderOnlyActiveTab: {
type: 'toggle',
displayName: 'Render only active tab',
+ section: 'additionalActions',
validation: {
schema: {
type: 'boolean',
@@ -106,37 +103,106 @@ export const tabsConfig = {
defaultValue: false,
},
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
+ tooltip: {
+ type: 'code',
+ displayName: 'Tooltip',
+ validation: { schema: { type: 'string' }, defaultValue: '' },
+ section: 'additionalActions',
+ placeholder: 'Enter tooltip text',
+ },
},
events: { onTabSwitch: { displayName: 'On tab switch' } },
styles: {
- highlightColor: {
+ headerBackground: {
type: 'colorSwatches',
- displayName: 'Highlight color',
+ displayName: 'Header background',
validation: {
schema: { type: 'string' },
- defaultValue: 'var(--primary-brand)',
+ defaultValue: 'var(--cc-surface1-surface)',
},
+ accordian: 'Tabs',
},
- visibility: {
- type: 'toggle',
- displayName: 'Visibility',
+ divider: {
+ type: 'colorSwatches',
+ displayName: 'Divider',
validation: {
- schema: {
- type: 'boolean',
- },
- defaultValue: false,
+ schema: { type: 'string' },
+ defaultValue: 'var(--cc-default-border)',
},
+ accordian: 'Tabs',
},
- disabledState: {
- type: 'toggle',
- displayName: 'Disable',
+ unselectedText: {
+ type: 'colorSwatches',
+ displayName: 'Unselected text',
validation: {
- schema: {
- type: 'boolean',
- },
- defaultValue: false,
+ schema: { type: 'string' },
+ defaultValue: '#375FCF',
},
+ accordian: 'Tabs',
},
+ selectedText: {
+ type: 'colorSwatches',
+ displayName: 'Selected text',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: 'var(--cc-primary-text)',
+ },
+ accordian: 'Tabs',
+ },
+ hoverBackground: {
+ type: 'colorSwatches',
+ displayName: 'Hover Background',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#1B1F24',
+ },
+ accordian: 'Tabs',
+ },
+ unselectedIcon: {
+ type: 'colorSwatches',
+ displayName: 'Unselected Icon',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#CCD1D5',
+ },
+ accordian: 'Tabs',
+ },
+ selectedIcon: {
+ type: 'colorSwatches',
+ displayName: 'Selected Icon',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#CCD1D5',
+ },
+ accordian: 'Tabs',
+ },
+ accent: {
+ type: 'colorSwatches',
+ displayName: 'Accent',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: 'var(--cc-primary-brand)',
+ },
+ accordian: 'Tabs',
+ },
+ // highlightColor: {
+ // type: 'colorSwatches',
+ // displayName: 'Highlight color',
+ // validation: {
+ // schema: { type: 'string' },
+ // defaultValue: '#375FCF',
+ // },
+ // accordian: 'Tabs',
+ // },
tabWidth: {
type: 'select',
displayName: 'Tab width',
@@ -144,6 +210,54 @@ export const tabsConfig = {
{ name: 'Auto', value: 'auto' },
{ name: 'Equally split', value: 'split' },
],
+ accordian: 'Tabs',
+ },
+ transition: {
+ type: 'select',
+ displayName: 'Transition',
+ options: [
+ { name: 'Slide', value: 'slide' },
+ { name: 'None', value: 'none' },
+ ],
+ accordian: 'Tabs',
+ },
+ border: {
+ type: 'colorSwatches',
+ displayName: 'Border',
+ validation: {
+ schema: { type: 'string' },
+ defaultValue: '#375FCF',
+ },
+ accordian: 'Container',
+ },
+ borderRadius: {
+ type: 'numberInput',
+ displayName: 'Border radius',
+ validation: {
+ validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
+ defaultValue: false,
+ },
+ accordian: 'Container',
+ },
+ boxShadow: {
+ type: 'boxShadow',
+ displayName: 'Box shadow',
+ validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
+ accordian: 'Container',
+ conditionallyRender: {
+ key: 'type',
+ value: 'primary',
+ },
+ },
+ padding: {
+ type: 'switch',
+ displayName: 'Padding',
+ validation: { schema: { type: 'string' } },
+ options: [
+ { displayName: 'Default', value: 'default' },
+ { displayName: 'None', value: 'none' },
+ ],
+ accordian: 'Container',
},
},
actions: [
@@ -157,28 +271,153 @@ export const tabsConfig = {
},
],
},
+ {
+ 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' }],
+ },
+ {
+ handle: 'setTabDisable',
+ displayName: 'Set Tab disable',
+ params: [
+ {
+ handle: 'tabId',
+ displayName: 'Tab',
+ type: 'select',
+ isDynamicOpiton: true,
+ optionsGetter: 'component.definition.properties.tabItems.value',
+ },
+ {
+ handle: 'value',
+ type: 'toggle',
+ displayName: 'Value',
+ defaultValue: '{{false}}',
+ },
+ ],
+ },
+ {
+ handle: 'setTabLoading',
+ displayName: 'Set Tab Loading',
+ params: [
+ {
+ handle: 'tabId',
+ displayName: 'Tab',
+ type: 'select',
+ isDynamicOpiton: true,
+ optionsGetter: 'component.definition.properties.tabItems.value',
+ },
+ {
+ handle: 'value',
+ type: 'toggle',
+ displayName: 'Value',
+ defaultValue: '{{false}}',
+ },
+ ],
+ },
+ {
+ handle: 'setTabVisibility',
+ displayName: 'Set Tab visibility',
+ params: [
+ {
+ handle: 'tabId',
+ displayName: 'Tab',
+ type: 'select',
+ isDynamicOpiton: true,
+ optionsGetter: 'component.definition.properties.tabItems.value',
+ },
+ {
+ handle: 'value',
+ type: 'toggle',
+ displayName: 'Value',
+ defaultValue: '{{false}}',
+ },
+ ],
+ },
],
- exposedVariables: { currentTab: '' },
+ exposedVariables: {
+ currentTab: '',
+ isVisible: true,
+ isDisabled: false,
+ isLoading: false,
+ },
definition: {
others: {
showOnDesktop: { value: '{{true}}' },
showOnMobile: { value: '{{false}}' },
},
properties: {
+ dynamicHeight: { value: '{{false}}' },
+ useDynamicOptions: { value: '{{false}}' },
tabs: {
value:
"{{[ \n\t\t{ title: 'Home', id: '0' }, \n\t\t{ title: 'Profile', id: '1' }, \n\t\t{ title: 'Settings', id: '2' } \n ]}}",
},
+ tabItems: {
+ value: [
+ {
+ id: 't0',
+ title: 'Tab 1',
+ icon: { value: 'IconHome2' },
+ iconVisibility: { value: false },
+ loading: { value: false },
+ disable: { value: false },
+ visible: { value: true },
+ },
+ {
+ id: 't1',
+ title: 'Tab 2',
+ icon: { value: 'IconHome2' },
+ iconVisibility: { value: false },
+ loading: { value: false },
+ disable: { value: false },
+ visible: { value: true },
+ },
+ {
+ id: 't2',
+ title: 'Tab 3',
+ icon: { value: 'IconHome2' },
+ iconVisibility: { value: false },
+ loading: { value: false },
+ disable: { value: false },
+ visible: { value: true },
+ },
+ ],
+ },
defaultTab: { value: '0' },
hideTabs: { value: false },
renderOnlyActiveTab: { value: false },
+ loadingState: { value: `{{false}}` },
+ visibility: { value: '{{true}}' },
+ disabledState: { value: '{{false}}' },
+ tooltip: { value: '' },
},
events: [],
styles: {
- highlightColor: { value: 'var(--primary-brand)' },
- visibility: { value: '{{true}}' },
- disabledState: { value: '{{false}}' },
+ headerBackground: { value: 'var(--cc-surface1-surface)' },
+ divider: { value: 'var(--cc-default-border)' },
+ unselectedText: { value: 'var(--cc-placeholder-text)' },
+ selectedText: { value: 'var(--cc-primary-text)' },
+ highlightColor: { value: 'var(--cc-primary-brand)' },
+ hoverBackground: { value: '#1B1F24' },
+ unselectedIcon: { value: 'var(--cc-default-icon)' },
+ selectedIcon: { value: 'var(--cc-default-icon)' },
+ accent: { value: 'var(--cc-primary-brand)' },
tabWidth: { value: 'auto' },
+ transition: { value: 'slide' },
+ borderRadius: { value: '{{6}}' },
+ border: { value: 'var(--cc-default-border)' },
+ boxShadow: { value: '0px 0px 0px 0px #121212' },
+ padding: { value: 'default' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/text.js b/frontend/src/AppBuilder/WidgetManager/widgets/text.js
index 8ed1edffd1..af9b637b32 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/text.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/text.js
@@ -29,6 +29,15 @@ export const textConfig = {
},
showLabel: false,
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
loadingState: {
type: 'toggle',
displayName: 'Show loading state',
@@ -267,6 +276,7 @@ export const textConfig = {
},
properties: {
textFormat: { value: 'html' },
+ dynamicHeight: { value: '{{false}}' },
text: { value: `Hello {{globals.currentUser.firstName}}👋` },
loadingState: { value: `{{false}}` },
disabledState: { value: '{{false}}' },
@@ -275,7 +285,7 @@ export const textConfig = {
events: [],
styles: {
backgroundColor: { value: '#fff00000' },
- textColor: { value: '#000000' },
+ textColor: { value: 'var(--cc-primary-text)' },
textSize: { value: '{{14}}' },
textAlign: { value: 'left' },
fontWeight: { value: 'normal' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/textarea.js b/frontend/src/AppBuilder/WidgetManager/widgets/textarea.js
index d0e0364334..ea5cf0d3ed 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/textarea.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/textarea.js
@@ -17,6 +17,15 @@ export const textareaConfig = {
displayName: 'Label',
validation: { schema: { type: 'string' }, defaultValue: 'Label' },
},
+ dynamicHeight: {
+ type: 'toggle',
+ displayName: 'Dynamic height',
+ validation: {
+ schema: { type: 'boolean' },
+ defaultValue: false,
+ },
+ section: 'additionalActions',
+ },
placeholder: {
type: 'code',
displayName: 'Placeholder',
@@ -80,9 +89,9 @@ export const textareaConfig = {
},
styles: {
color: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -132,33 +141,33 @@ export const textareaConfig = {
},
backgroundColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -169,9 +178,9 @@ export const textareaConfig = {
visibility: false,
},
iconColor: {
- type: 'color',
+ type: 'colorSwatches',
displayName: 'Icon color',
- validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
accordian: 'field',
visibility: false,
showLabel: false,
@@ -274,6 +283,7 @@ export const textareaConfig = {
value: { value: '' },
label: { value: 'Label' },
placeholder: { value: 'Enter your input' },
+ dynamicHeight: { value: '{{false}}' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
loadingState: { value: '{{false}}' },
@@ -281,17 +291,17 @@ export const textareaConfig = {
},
events: [],
styles: {
- textColor: { value: '#1B1F24' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- errTextColor: { value: '#D72D39' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
- iconColor: { value: '#CFD3D859' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
- color: { value: '#1B1F24' },
+ color: { value: 'var(--cc-primary-text)' },
auto: { value: '{{true}}' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js
index e259ecddd0..4da69a7e77 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/textinput.js
@@ -82,7 +82,7 @@ export const textinputConfig = {
color: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -134,31 +134,31 @@ export const textinputConfig = {
backgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
borderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: 'var(--primary-brand)' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
textColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#D72D39' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -171,7 +171,7 @@ export const textinputConfig = {
iconColor: {
type: 'colorSwatches',
displayName: 'Icon color',
- validation: { schema: { type: 'string' }, defaultValue: '#CFD3D859' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-icon)' },
accordian: 'field',
visibility: false,
showLabel: false,
@@ -281,17 +281,17 @@ export const textinputConfig = {
},
events: [],
styles: {
- textColor: { value: '#1B1F24' },
- borderColor: { value: '#CCD1D5' },
- accentColor: { value: 'var(--primary-brand)' },
- errTextColor: { value: '#D72D39' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
borderRadius: { value: '{{6}}' },
- backgroundColor: { value: '#fff' },
- iconColor: { value: '#CFD3D859' },
+ backgroundColor: { value: 'var(--cc-surface1-surface)' },
+ iconColor: { value: 'var(--cc-default-icon)' },
direction: { value: 'left' },
width: { value: '{{33}}' },
alignment: { value: 'side' },
- color: { value: '#1B1F24' },
+ color: { value: 'var(--cc-primary-text)' },
auto: { value: '{{true}}' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/timeline.js b/frontend/src/AppBuilder/WidgetManager/widgets/timeline.js
index 63776f0b99..212f8bc480 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/timeline.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/timeline.js
@@ -48,7 +48,7 @@ export const timelineConfig = {
properties: {
data: {
value:
- "{{ [ \n\t\t{ title: 'Product Launched', subTitle: 'First version of our product released to public', date: '20/10/2021', iconBackgroundColor: 'var(--primary-brand)'},\n\t\t { title: 'First Signup', subTitle: 'Congratulations! We got our first signup', date: '22/10/2021', iconBackgroundColor: 'var(--primary-brand)'}, \n\t\t { title: 'First Payment', subTitle: 'Hurray! We got our first payment', date: '01/11/2021', iconBackgroundColor: 'var(--primary-brand)'} \n] }}",
+ "{{ [ \n\t\t{ title: 'Product Launched', subTitle: 'First version of our product released to public', date: '20/10/2021', iconBackgroundColor: 'var(--cc-primary-brand)'},\n\t\t { title: 'First Signup', subTitle: 'Congratulations! We got our first signup', date: '22/10/2021', iconBackgroundColor: 'var(--cc-primary-brand)'}, \n\t\t { title: 'First Payment', subTitle: 'Hurray! We got our first payment', date: '01/11/2021', iconBackgroundColor: 'var(--cc-primary-brand)'} \n] }}",
},
hideDate: { value: '{{false}}' },
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/timepicker.js b/frontend/src/AppBuilder/WidgetManager/widgets/timepicker.js
index a5a1fb6b06..9b23523249 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/timepicker.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/timepicker.js
@@ -166,7 +166,7 @@ export const timePickerConfig = {
labelColor: {
type: 'colorSwatches',
displayName: 'Color',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'label',
},
alignment: {
@@ -217,31 +217,31 @@ export const timePickerConfig = {
fieldBackgroundColor: {
type: 'colorSwatches',
displayName: 'Background',
- validation: { schema: { type: 'string' }, defaultValue: '#fff' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
accordian: 'field',
},
fieldBorderColor: {
type: 'colorSwatches',
displayName: 'Border',
- validation: { schema: { type: 'string' }, defaultValue: '#CCD1D5' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-default-border)' },
accordian: 'field',
},
accentColor: {
type: 'colorSwatches',
displayName: 'Accent',
- validation: { schema: { type: 'string' }, defaultValue: '#4368E3' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-brand)' },
accordian: 'field',
},
selectedTextColor: {
type: 'colorSwatches',
displayName: 'Text',
- validation: { schema: { type: 'string' }, defaultValue: '#1B1F24' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-primary-text)' },
accordian: 'field',
},
errTextColor: {
type: 'colorSwatches',
displayName: 'Error text',
- validation: { schema: { type: 'string' }, defaultValue: '#E54D2E' },
+ validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-error-systemStatus)' },
accordian: 'field',
},
icon: {
@@ -257,7 +257,7 @@ export const timePickerConfig = {
showLabel: false,
validation: {
schema: { type: 'string' },
- defaultValue: '#6A727C',
+ defaultValue: 'var(--cc-default-icon)',
},
accordian: 'field',
},
@@ -331,23 +331,23 @@ export const timePickerConfig = {
},
events: [],
styles: {
- labelColor: { value: '#1B1F24' },
+ labelColor: { value: 'var(--cc-primary-text)' },
alignment: { value: 'side' },
direction: { value: 'left' },
labelWidth: { value: '20' },
auto: { value: '{{true}}' },
- fieldBackgroundColor: { value: '#fff' },
- fieldBorderColor: { value: '#CCD1D5' },
- accentColor: { value: '#4368E3' },
- selectedTextColor: { value: '#1B1F24' },
- errTextColor: { value: '#E54D2E' },
+ fieldBackgroundColor: { value: 'var(--cc-surface1-surface)' },
+ fieldBorderColor: { value: 'var(--cc-default-border)' },
+ accentColor: { value: 'var(--cc-primary-brand)' },
+ selectedTextColor: { value: 'var(--cc-primary-text)' },
+ errTextColor: { value: 'var(--cc-error-systemStatus)' },
icon: { value: 'IconClock' },
iconVisibility: { value: true },
iconDirection: { value: 'left' },
fieldBorderRadius: { value: '{{6}}' },
boxShadow: { value: '0px 0px 0px 0px #121212' },
padding: { value: 'default' },
- iconColor: { value: '#6A727C' },
+ iconColor: { value: 'var(--cc-default-icon)' },
},
},
};
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitch.js b/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitch.js
index bd646a47f3..4aa6c10c58 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitch.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitch.js
@@ -74,8 +74,8 @@ export const toggleswitchConfig = {
},
events: [],
styles: {
- textColor: { value: '' },
- toggleSwitchColor: { value: 'var(--primary-brand)' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ toggleSwitchColor: { value: 'var(--cc-primary-brand)' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitchv2.js b/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitchv2.js
index 4b31bc8f0c..aec87dc17c 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitchv2.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/toggleswitchv2.js
@@ -194,11 +194,11 @@ export const toggleSwitchV2Config = {
},
events: [],
styles: {
- textColor: { value: '#1B1F24' },
- toggleSwitchColor: { value: 'var(--primary-brand)' }, //keeping same key for backward comopatibility
- uncheckedColor: { value: '#E4E7EB' },
- borderColor: { value: '#E4E7EB' },
- handleColor: { value: '#FFFFFF' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ toggleSwitchColor: { value: 'var(--cc-primary-brand)' }, //keeping same key for backward comopatibility
+ uncheckedColor: { value: 'var(--cc-surface3-surface)' },
+ borderColor: { value: 'var(--cc-default-border)' },
+ handleColor: { value: 'var(--cc-surface1-surface)' },
alignment: { value: 'right' },
boxShadow: { value: '0px 0px 0px 0px #00000090' },
padding: { value: 'default' },
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/treeSelect.js b/frontend/src/AppBuilder/WidgetManager/widgets/treeSelect.js
index 898f0b3ed0..68e16b107c 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/treeSelect.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/treeSelect.js
@@ -70,8 +70,8 @@ export const treeSelectConfig = {
},
events: [],
styles: {
- textColor: { value: '' },
- checkboxColor: { value: 'var(--primary-brand)' },
+ textColor: { value: 'var(--cc-primary-text)' },
+ checkboxColor: { value: 'var(--cc-primary-brand)' },
visibility: { value: '{{true}}' },
disabledState: { value: '{{false}}' },
},
diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js b/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js
index df426c7b5f..a75d0528e2 100644
--- a/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js
+++ b/frontend/src/AppBuilder/WidgetManager/widgets/verticalDivider.js
@@ -36,7 +36,7 @@ export const verticalDividerConfig = {
displayName: 'Divider color',
validation: {
schema: { type: 'string' },
- defaultValue: '#000000',
+ defaultValue: 'var(--cc-default-border)',
},
accordian: 'Divider',
},
@@ -90,7 +90,7 @@ export const verticalDividerConfig = {
},
events: [],
styles: {
- dividerColor: { value: '#CCD1D5' },
+ dividerColor: { value: 'var(--cc-default-border)' },
dividerStyle: { value: 'solid' },
padding: { value: 'default' },
boxShadow: { value: '0px 0px 0px 0px #00000040' },
diff --git a/frontend/src/AppBuilder/Widgets/BaseComponents/BaseInput.jsx b/frontend/src/AppBuilder/Widgets/BaseComponents/BaseInput.jsx
index 74ce215737..f49f9268c9 100644
--- a/frontend/src/AppBuilder/Widgets/BaseComponents/BaseInput.jsx
+++ b/frontend/src/AppBuilder/Widgets/BaseComponents/BaseInput.jsx
@@ -2,6 +2,7 @@ import React, { forwardRef } from 'react';
import Label from '@/_ui/Label';
import Loader from '@/ToolJetUI/Loader/Loader';
import * as Icons from '@tabler/icons-react';
+import { getModifiedColor } from '@/Editor/Components/utils';
const tinycolor = require('tinycolor2');
const RenderInput = forwardRef((props, ref) => {
@@ -78,7 +79,7 @@ export const BaseInput = ({
: disable || loading
? '1px solid var(--borders-disabled-on-white)'
: 'var(--borders-default)',
- '--tblr-input-border-color-darker': tinycolor(borderColor).darken(24).toString(),
+ '--tblr-input-border-color-darker': getModifiedColor(borderColor, 24),
backgroundColor:
backgroundColor != '#fff'
? backgroundColor
@@ -211,7 +212,7 @@ export const BaseInput = ({
onBlur={handleBlur}
onFocus={handleFocus}
onKeyUp={handleKeyUp}
- disabled={disable || loading}
+ // disabled={disable || loading}
placeholder={placeholder}
style={finalStyles}
{...additionalInputProps}
diff --git a/frontend/src/AppBuilder/Widgets/Container/Container.jsx b/frontend/src/AppBuilder/Widgets/Container/Container.jsx
index a706d29069..61775f5919 100644
--- a/frontend/src/AppBuilder/Widgets/Container/Container.jsx
+++ b/frontend/src/AppBuilder/Widgets/Container/Container.jsx
@@ -3,12 +3,15 @@ import { Container as ContainerComponent } from '@/AppBuilder/AppCanvas/Containe
import Spinner from '@/_ui/Spinner';
import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables';
import { shallow } from 'zustand/shallow';
+import { useDynamicHeight } from '@/_hooks/useDynamicHeight';
import {
CONTAINER_FORM_CANVAS_PADDING,
SUBCONTAINER_CANVAS_BORDER_WIDTH,
} from '@/AppBuilder/AppCanvas/appCanvasConstants';
import useStore from '@/AppBuilder/_stores/store';
import './container.scss';
+import { useActiveSlot } from '@/AppBuilder/_hooks/useActiveSlot';
+import { HorizontalSlot } from '@/AppBuilder/Widgets/Form/Components/HorizontalSlot';
export const Container = ({
id,
@@ -19,6 +22,9 @@ export const Container = ({
width,
setExposedVariables,
setExposedVariable,
+ adjustComponentPositions,
+ currentLayout,
+ componentCount = 0,
}) => {
const { isDisabled, isVisible, isLoading } = useExposeState(
properties.loadingState,
@@ -28,13 +34,30 @@ export const Container = ({
setExposedVariable
);
+ const { dynamicHeight } = properties;
+
+ useDynamicHeight({
+ dynamicHeight: properties.dynamicHeight,
+ id,
+ height,
+ adjustComponentPositions,
+ currentLayout,
+ isContainer: true,
+ componentCount,
+ });
+
const isWidgetInContainerDragging = useStore(
(state) => state.containerChildrenMapping?.[id]?.includes(state?.draggingComponentId),
shallow
);
+ const isEditing = useStore((state) => state.currentMode === 'edit');
+ const setComponentProperty = useStore((state) => state.setComponentProperty, shallow);
+
+ const activeSlot = useActiveSlot(isEditing ? id : null); // Track the active slot for this widget
const { borderRadius, borderColor, boxShadow } = styles;
const { headerHeight = 80 } = properties;
+ const headerMaxHeight = parseInt(height, 10) - 100 - 10;
const contentBgColor = useMemo(() => {
return {
backgroundColor:
@@ -55,7 +78,7 @@ export const Container = ({
backgroundColor: contentBgColor.backgroundColor,
borderRadius: borderRadius ? parseFloat(borderRadius) : 0,
border: `${SUBCONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`,
- height,
+ height: dynamicHeight ? '100%' : height,
display: isVisible ? 'flex' : 'none',
flexDirection: 'column',
position: 'relative',
@@ -65,9 +88,9 @@ export const Container = ({
const containerHeaderStyles = {
flexShrink: 0,
padding: `${CONTAINER_FORM_CANVAS_PADDING}px ${CONTAINER_FORM_CANVAS_PADDING}px 3px ${CONTAINER_FORM_CANVAS_PADDING}px`,
+ maxHeight: `${headerMaxHeight}px`,
...headerBgColor,
};
-
const containerContentStyles = {
overflow: 'hidden auto',
display: 'flex',
@@ -75,6 +98,11 @@ export const Container = ({
padding: `${CONTAINER_FORM_CANVAS_PADDING}px`,
};
+ const updateHeaderSizeInStore = ({ newHeight }) => {
+ const _height = parseInt(newHeight, 10);
+ setComponentProperty(id, `headerHeight`, _height, 'properties', 'value', false);
+ };
+
return (
{properties.showHeader && (
-
-
-
+
)}
-
+
{
const {
@@ -43,6 +44,9 @@ const CustomDatePickerHeader = (props) => {
const years = range(1900, 2101);
+ const menuHoverColor = getModifiedColor('var(--cc-surface1-surface)', 'hover');
+ const menuActiveColor = getModifiedColor('var(--cc-surface1-surface)', 'active');
+
const customSelectStyles = {
control: (provided) => ({
...provided,
@@ -82,6 +86,7 @@ const CustomDatePickerHeader = (props) => {
width: '150px',
borderRadius: '8px',
top: 'auto',
+ backgroundColor: 'var(--cc-surface1-surface) !important',
}),
menuList: (provided) => ({
...provided,
@@ -90,14 +95,10 @@ const CustomDatePickerHeader = (props) => {
overflowY: 'auto', // Enable scrolling if needed
scrollbarWidth: 'none', // Hide scrollbar for Firefox
borderRadius: '8px',
+ backgroundColor: 'var(--cc-surface1-surface) !important',
}),
option: (provided, state) => ({
...provided,
- backgroundColor: state.isFocused
- ? '#f0f0f0' // Hover color
- : state.isSelected
- ? '#e6e6e6' // Selected background color
- : 'white',
color: state.isSelected ? '#333' : 'black', // Adjust text color for selected state
paddingLeft: '20px',
position: 'relative',
@@ -117,7 +118,7 @@ const CustomDatePickerHeader = (props) => {
}}
>
{isSelected && (
-
+
)}
{data.label}
@@ -133,6 +134,8 @@ const CustomDatePickerHeader = (props) => {
marginTop: 10,
display: 'flex',
justifyContent: 'center',
+ '--cc-date-dropdown-hover': menuHoverColor,
+ '--cc-date-dropdown-active': menuActiveColor,
}}
>
{!(datepickerSelectionType === 'range' && customHeaderCount === 1) && (
@@ -145,7 +148,7 @@ const CustomDatePickerHeader = (props) => {
}}
disabled={datepickerMode === 'date' ? prevMonthButtonDisabled : prevYearButtonDisabled}
>
-
+
)}
@@ -207,7 +210,7 @@ const CustomDatePickerHeader = (props) => {
}}
disabled={datepickerMode === 'date' ? nextMonthButtonDisabled : nextYearButtonDisabled}
>
-
+
)}
diff --git a/frontend/src/AppBuilder/Widgets/Date/DatepickerInput.jsx b/frontend/src/AppBuilder/Widgets/Date/DatepickerInput.jsx
index d9a13400a1..a5d77d7367 100644
--- a/frontend/src/AppBuilder/Widgets/Date/DatepickerInput.jsx
+++ b/frontend/src/AppBuilder/Widgets/Date/DatepickerInput.jsx
@@ -59,7 +59,7 @@ export const DatepickerInput = forwardRef(
}
}
}}
- disabled={disable || loading}
+ // disabled={disable || loading}
/>
diff --git a/frontend/src/AppBuilder/Widgets/Date/DaterangePicker.jsx b/frontend/src/AppBuilder/Widgets/Date/DaterangePicker.jsx
index ceb7504b60..f3bc2bf942 100644
--- a/frontend/src/AppBuilder/Widgets/Date/DaterangePicker.jsx
+++ b/frontend/src/AppBuilder/Widgets/Date/DaterangePicker.jsx
@@ -4,6 +4,7 @@ import { BaseDateComponent } from './BaseDateComponent';
import moment from 'moment-timezone';
import cx from 'classnames';
import { isDateRangeValid, isDateValid } from './utils';
+import './styles.scss';
export const DaterangePicker = ({
height,
diff --git a/frontend/src/AppBuilder/Widgets/Date/TimepickerInput.jsx b/frontend/src/AppBuilder/Widgets/Date/TimepickerInput.jsx
index aa5be134d1..18ed4ea59a 100644
--- a/frontend/src/AppBuilder/Widgets/Date/TimepickerInput.jsx
+++ b/frontend/src/AppBuilder/Widgets/Date/TimepickerInput.jsx
@@ -45,7 +45,7 @@ const TimepickerInput = ({ currentTimestamp, isTwentyFourHourMode, darkMode, onT
};
return (
-
+
{headers.map((header) => (
diff --git a/frontend/src/AppBuilder/Widgets/Date/styles.scss b/frontend/src/AppBuilder/Widgets/Date/styles.scss
new file mode 100644
index 0000000000..e7f127e8c0
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/Date/styles.scss
@@ -0,0 +1,40 @@
+.tj-daterange-widget {
+ .react-datepicker {
+ .react-datepicker__header {
+ background-color: var(--cc-surface1-surface);
+ }
+ }
+}
+
+.tj-table-datepicker .react-datepicker__day--keyboard-selected {
+ background-color: var(--cc-surface1-surface) !important;
+}
+
+.react-datepicker__day:not([aria-disabled=true]):hover {
+ border-radius: 0.3rem;
+ background-color: var(--cc-surface1-surface) !important;
+ filter: brightness(0.92);
+}
+
+.react-datepicker__day--keyboard-selected {
+ background-color: var(--cc-surface1-surface) !important;
+}
+
+.daterangepicker-header {
+ .react-select__menu .react-select__menu-list {
+ background-color: var(--cc-surface1-surface) !important;
+ }
+
+ .react-select__menu .react-select__menu-list .react-select__option {
+ background-color: var(--cc-surface1-surface) !important;
+ }
+
+ .react-select__menu .react-select__menu-list .react-select__option:hover {
+ background-color: var(--cc-date-dropdown-hover) !important;
+ }
+
+ .react-select__menu .react-select__menu-list .react-select__option:active {
+ background-color: var(--cc-date-dropdown-active) !important;
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/Components/ErrorMessage.jsx b/frontend/src/AppBuilder/Widgets/FilePicker/Components/ErrorMessage.jsx
new file mode 100644
index 0000000000..229b7a5f51
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/Components/ErrorMessage.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Information from '@/_ui/Icon/solidIcons/Information';
+
+const ErrorMessage = ({ message }) => {
+ return (
+
+
+
+
+ {message}
+
+ );
+};
+
+ErrorMessage.propTypes = {
+ message: PropTypes.string.isRequired,
+};
+
+export default ErrorMessage;
\ No newline at end of file
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/Components/FileList.jsx b/frontend/src/AppBuilder/Widgets/FilePicker/Components/FileList.jsx
new file mode 100644
index 0000000000..64f83df3c5
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/Components/FileList.jsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import FileListItem from './FileListItem';
+import { formatFileSize } from '@/_helpers/utils';
+
+const FileList = ({ files, onRemoveFile, errors = {}, uploadingStatus = {} }) => {
+ // TODO: Need to get file size formatting function, e.g., from @/_helpers/utils
+ // const formatFileSize = (bytes) => { ... }; // Placeholder
+
+ return (
+
+ {files.map((file, index) => {
+ // Extract file extension for display if needed
+ const fileExtension = file.name.split('.').pop();
+ // Determine error state for this specific file
+ const fileError = errors[file.name] || null; // Example: Assuming errors object is keyed by file name
+ // Determine uploading state for this specific file
+ const isUploading = uploadingStatus[file.name] === 'uploading'; // Example: Assuming status object
+ const isUploaded = uploadingStatus[file.name] === 'uploaded'; // Example: Assuming status object
+
+ return (
+ onRemoveFile(index)} // Pass index or file identifier to remove function
+ onClick={() => {
+ /* Handle click if needed */
+ }}
+ error={fileError}
+ isUploading={isUploading}
+ isUploaded={isUploaded}
+ // Pass other necessary props based on FileListItem implementation
+ />
+ );
+ })}
+
+ );
+};
+
+FileList.propTypes = {
+ files: PropTypes.arrayOf(
+ PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ size: PropTypes.number, // Size might not always be present initially
+ type: PropTypes.string,
+ // Include other expected file properties if needed
+ })
+ ).isRequired,
+ onRemoveFile: PropTypes.func.isRequired,
+ errors: PropTypes.object, // Shape depends on how errors are structured
+ uploadingStatus: PropTypes.object, // Shape depends on how status is structured
+};
+
+export default FileList;
\ No newline at end of file
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/Components/FileListItem.jsx b/frontend/src/AppBuilder/Widgets/FilePicker/Components/FileListItem.jsx
new file mode 100644
index 0000000000..f499f59437
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/Components/FileListItem.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import { ButtonSolid } from '@/_ui/AppButton/AppButton';
+import Trash from '@/_ui/Icon/solidIcons/Trash';
+import '../style.scss';
+
+const FileListItem = ({ fileName, fileSize, fileType, onDelete, onClick, error, isUploading, isUploaded }) => {
+ const itemClasses = clsx('file-list-item', {
+ error: !!error,
+ uploading: isUploading,
+ });
+
+ return (
+
+
+
+ {fileName}
+
+
+ {fileType} {fileSize}
+
+
+
+ {!isUploading && (
+
{
+ event.stopPropagation();
+ onDelete();
+ }}
+ >
+
+
+ )}
+
+ );
+};
+
+FileListItem.propTypes = {
+ fileName: PropTypes.string.isRequired,
+ fileSize: PropTypes.string.isRequired,
+ fileType: PropTypes.string.isRequired,
+ onDelete: PropTypes.func.isRequired,
+ onClick: PropTypes.func.isRequired,
+ error: PropTypes.string,
+ isUploading: PropTypes.bool,
+ isUploaded: PropTypes.bool,
+};
+
+FileListItem.defaultProps = {
+ error: null,
+ isUploading: false,
+ isUploaded: false,
+};
+
+export default FileListItem;
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/Components/UploadArea.jsx b/frontend/src/AppBuilder/Widgets/FilePicker/Components/UploadArea.jsx
new file mode 100644
index 0000000000..033ffef65c
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/Components/UploadArea.jsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import SolidIcon from '@/_ui/Icon/SolidIcons';
+import ErrorMessage from './ErrorMessage';
+import { formatFileSize } from '@/_helpers/utils';
+
+// Renamed from DropzoneArea
+const UploadArea = ({
+ getRootProps,
+ getInputProps,
+ isDragActive,
+ isDragAccept,
+ isDragReject,
+ isDisabled,
+ isFocused,
+ uiErrorMessage,
+ onFocus,
+ onBlur,
+ borderRadius,
+ height,
+ instructionText,
+ minSize,
+ maxSize,
+ maxCount,
+ fileTypeCategory,
+ selectedFilesLength,
+}) => {
+ // --- Refactored Conditions for Readability ---
+ const canShowInstructionText = !isDragActive && selectedFilesLength < maxCount;
+ const showGenericDropMessage = isDragActive && !isDragAccept && !isDragReject;
+ const showAcceptDropMessage = isDragActive && isDragAccept;
+ const showRejectDropMessage = isDragActive && isDragReject;
+ const showDisabledMessage = isDisabled && selectedFilesLength >= maxCount;
+ const hasUiError = uiErrorMessage && uiErrorMessage.trim() !== '.';
+ // --- End Refactored Conditions ---
+
+ const dropzoneClasses = [
+ 'file-picker-dropzone',
+ isDragActive ? 'is-dragging' : '',
+ isDragAccept ? 'is-accepting' : '',
+ isDragReject ? 'is-rejecting' : '',
+ isFocused ? 'is-focused' : '',
+ isDisabled ? 'is-disabled' : '',
+ ]
+ .filter(Boolean)
+ .join(' ');
+
+ return (
+
+
+
+ {hasUiError && (
+
+
+
+ )}
+
+ {!hasUiError && (
+ <>
+ {canShowInstructionText &&
{instructionText}
}
+
+ {showGenericDropMessage &&
Drop the files here ...
}
+ {showAcceptDropMessage && (
+
+
+ Drop file to start uploading
+
+ )}
+ {showRejectDropMessage &&
Cannot upload these files
}
+ {showDisabledMessage &&
Maximum files uploaded
}
+ >
+ )}
+
+ );
+};
+
+UploadArea.propTypes = {
+ getRootProps: PropTypes.func.isRequired,
+ getInputProps: PropTypes.func.isRequired,
+ isDragActive: PropTypes.bool.isRequired,
+ isDragAccept: PropTypes.bool.isRequired,
+ isDragReject: PropTypes.bool.isRequired,
+ isDisabled: PropTypes.bool.isRequired,
+ isFocused: PropTypes.bool.isRequired,
+ instructionText: PropTypes.string.isRequired,
+ uiErrorMessage: PropTypes.string,
+ onFocus: PropTypes.func.isRequired,
+ onBlur: PropTypes.func.isRequired,
+ borderRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ boxShadow: PropTypes.string,
+ height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ minSize: PropTypes.number,
+ maxSize: PropTypes.number,
+ maxCount: PropTypes.number,
+ fileTypeCategory: PropTypes.string,
+};
+
+UploadArea.defaultProps = {
+ borderRadius: 6,
+ boxShadow: '',
+ height: '100%',
+ uiErrorMessage: '.',
+ minSize: 0,
+ maxSize: Number.POSITIVE_INFINITY,
+ maxCount: Number.POSITIVE_INFINITY,
+ fileTypeCategory: '*/*',
+};
+
+export default UploadArea;
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/Components/ValidationBar.jsx b/frontend/src/AppBuilder/Widgets/FilePicker/Components/ValidationBar.jsx
new file mode 100644
index 0000000000..25b04b3115
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/Components/ValidationBar.jsx
@@ -0,0 +1,78 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { formatFileSize } from '@/_helpers/utils'; // Import the utility
+
+const ValidationBar = ({
+ minSize,
+ maxSize,
+ selectedFileCount,
+ minFileCount, // Added minFileCount prop
+ maxFileCount,
+ enableMultiple,
+}) => {
+ const showSizeValidation = minSize > 0 || (maxSize > 0 && maxSize < Infinity); // Check if size limits are meaningful
+ // Show count validation if multiple files are enabled OR if a minimum is set (even for single file upload)
+ const showCountValidation = enableMultiple || minFileCount > 0;
+
+ // Don't render if no validation info is relevant
+ if (!showSizeValidation && !showCountValidation) {
+ return null;
+ }
+
+ // Helper to construct count text
+ const getCountText = () => {
+ if (!showCountValidation) return null;
+
+ const maxCountText = maxFileCount > 0 ? `${maxFileCount}` : 'any';
+
+ if (minFileCount > 0 && maxFileCount > 0 && minFileCount !== maxFileCount) {
+ // Min and Max count differ
+ return `${selectedFileCount} (${minFileCount}-${maxCountText} files)`;
+ } else if (minFileCount > 0 && (maxFileCount <= 0 || minFileCount === maxFileCount)) {
+ // Only Min count (or min equals max)
+ return `${selectedFileCount} (Min ${minFileCount} file${minFileCount !== 1 ? 's' : ''})`;
+ } else if (maxFileCount > 0) {
+ // Only Max count (standard case)
+ return `${selectedFileCount}/${maxCountText}`;
+ }
+ return null; // Should not happen if showCountValidation is true
+ };
+
+ const countText = getCountText();
+
+ return (
+
+ {/* Size Validation Info */}
+ {showSizeValidation && (
+
+ {minSize > 0 && maxSize < Infinity
+ ? `${formatFileSize(minSize)} to ${formatFileSize(maxSize)}` // Min and Max
+ : maxSize < Infinity && maxSize > 0
+ ? `Up to ${formatFileSize(maxSize)}` // Only Max
+ : `Min ${formatFileSize(minSize)}`}
+
+ )}
+
+ {countText && {countText}}
+
+ );
+};
+
+ValidationBar.propTypes = {
+ minSize: PropTypes.number,
+ maxSize: PropTypes.number,
+ selectedFileCount: PropTypes.number.isRequired,
+ minFileCount: PropTypes.number, // Added prop type
+ maxFileCount: PropTypes.number,
+ enableMultiple: PropTypes.bool,
+};
+
+ValidationBar.defaultProps = {
+ minSize: 0,
+ maxSize: Infinity, // Use Infinity for no practical upper limit
+ minFileCount: 0, // Default min count
+ maxFileCount: 0, // Default to 0 if not multiple or specified
+ enableMultiple: false,
+};
+
+export default ValidationBar;
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/FilePicker.jsx b/frontend/src/AppBuilder/Widgets/FilePicker/FilePicker.jsx
new file mode 100644
index 0000000000..d480cb9ac4
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/FilePicker.jsx
@@ -0,0 +1,269 @@
+import React, { useMemo, useState, useEffect, useRef } from 'react';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import { formatFileSize } from '@/_helpers/utils';
+
+import FileList from './Components/FileList';
+import UploadArea from './Components/UploadArea';
+import ValidationBar from './Components/ValidationBar';
+import ErrorMessage from './Components/ErrorMessage';
+import './style.scss';
+import { useFilePicker } from './hooks/useFilePicker';
+import Loader from '@/ToolJetUI/Loader/Loader';
+import { getModifiedColor } from '@/Editor/Components/utils';
+
+const FilePicker = (props) => {
+ const {
+ id,
+ width,
+ height,
+ component,
+ fireEvent,
+ onComponentOptionChanged,
+ darkMode,
+ styles,
+ properties,
+ validation,
+ setExposedVariable,
+ setExposedVariables,
+ dataCy,
+ } = props;
+
+ const numericWidgetHeight = Number.parseFloat(String(height).replace('px', '')) || 0; // Default to 0 if parsing fails
+ const isSmallWidget = numericWidgetHeight < 200;
+
+ const {
+ getRootProps,
+ getInputProps,
+ isDragActive,
+ isDragAccept,
+ isDragReject,
+ selectedFiles,
+ fileErrors,
+ uploadingStatus,
+ isParsing,
+ handleRemoveFile,
+ labelText,
+ instructionText,
+ disablePicker,
+ disabledState,
+ isVisible,
+ isLoading,
+ isMandatory,
+ minFileCount,
+ maxFileCount,
+ dropzoneRejections,
+ uiErrorMessage,
+ containerBackgroundColor,
+ borderRadius,
+ containerBorder,
+ containerBoxShadow,
+ containerPadding,
+ dropzoneTitleColor,
+ dropzoneActiveColor,
+ dropzoneErrorColor,
+ } = useFilePicker({ ...props, setExposedVariable, setExposedVariables });
+
+ const rootRef = useRef(null);
+
+ useEffect(() => {
+ if (!rootRef.current) return;
+ if (dropzoneActiveColor) {
+ rootRef.current.style.setProperty('--file-picker-primary-brand', dropzoneActiveColor);
+ }
+ if (dropzoneErrorColor) {
+ rootRef.current.style.setProperty('--file-picker-error-strong', dropzoneErrorColor);
+ }
+ if (dropzoneTitleColor) {
+ rootRef.current.style.setProperty('--file-picker-text-primary', dropzoneTitleColor);
+ }
+ if (borderRadius !== undefined) {
+ rootRef.current.style.setProperty(
+ '--file-picker-border-radius',
+ typeof borderRadius === 'number' ? `${borderRadius}px` : borderRadius
+ );
+ }
+ if (containerBackgroundColor) {
+ rootRef.current.style.setProperty('--file-picker-background-color', containerBackgroundColor);
+ }
+ if (containerBorder) {
+ rootRef.current.style.setProperty('--file-picker-border', containerBorder);
+ }
+ if (containerBoxShadow) {
+ rootRef.current.style.setProperty('--file-picker-box-shadow', containerBoxShadow);
+ }
+ if (containerPadding !== undefined) {
+ rootRef.current.style.setProperty(
+ '--file-picker-padding',
+ typeof containerPadding === 'number' ? `${containerPadding}px` : containerPadding
+ );
+ }
+
+ }, [
+ dropzoneActiveColor,
+ dropzoneErrorColor,
+ dropzoneTitleColor,
+ borderRadius,
+ containerBackgroundColor,
+ containerBorder,
+ containerBoxShadow,
+ containerPadding,
+ darkMode,
+ ]);
+
+ const [isFocused, setIsFocused] = useState(false);
+
+ const dynamicDropzoneStyle = useMemo(
+ () => ({
+ display: isVisible ? 'flex' : 'none',
+ backgroundColor: 'var(--cc-surface1-surface)',
+ color: darkMode ? '#c3c9d2' : '#5e6571',
+ height: `${numericWidgetHeight}px`,
+ overflowY: isSmallWidget ? 'auto' : 'visible',
+ opacity: disabledState ? 0.5 : 1,
+ }),
+ [darkMode, numericWidgetHeight, isVisible, isSmallWidget, disabledState]
+ );
+
+ if (rootRef?.current) {
+ rootRef.current.style.setProperty(
+ '--file-picker-delete-button-hover-bg',
+ getModifiedColor('var(--cc-surface1-surface)', 'hover')
+ );
+ }
+
+ const dropzoneClasses = clsx('file-picker-dropzone', {
+ 'is-dragging': isDragActive,
+ 'is-accepting': isDragAccept,
+ 'is-rejecting': isDragReject,
+ 'is-disabled': disabledState || disablePicker,
+ 'is-focused': isFocused,
+ });
+
+ const widgetVisibility = styles?.visibility ?? true;
+ if (!widgetVisibility) {
+ return null;
+ }
+
+ const handleFocus = () => {
+ if (!disabledState) {
+ setIsFocused(true);
+ }
+ };
+
+ const handleBlur = () => {
+ setIsFocused(false);
+ };
+
+ const rootProps = getRootProps({ className: dropzoneClasses });
+ const inputProps = getInputProps();
+
+ const augmentedInputProps = {
+ ...inputProps,
+ onFocus: handleFocus,
+ onBlur: handleBlur,
+ };
+
+ const { enableMultiple } = properties;
+ const { minSize, maxSize, fileType } = validation;
+
+ // const filePaneClasses = clsx(
+ // 'file-picker-files-pane',
+ // isSmallWidget
+ // ? 'h-auto overflow-y-visible'
+ // : selectedFiles.length > 4
+ // ? 'overflow-y-auto max-h-[38.2%] min-h-[180px]'
+ // : 'h-auto overflow-y-auto'
+ // );
+
+ const filePaneClasses = clsx(
+ 'file-picker-files-pane tw-p-2 tw-pt-0'
+ );
+
+ const topSectionClasses = clsx('tw-flex tw-flex-col tw-shrink-0 tw-grow tw-p-4', {
+ 'tw-flex-grow': selectedFiles.length === 0,
+ });
+
+ return (
+
+ {isLoading ? (
+
+
+
+ ) : (
+ <>
+
+
+ {labelText || 'Upload files'}
+
+
+
+
+ {selectedFiles.length > 0 && (
+
+
+
+ )}
+ >
+ )}
+
+ );
+};
+
+FilePicker.propTypes = {
+ id: PropTypes.string.isRequired,
+ width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ component: PropTypes.object,
+ fireEvent: PropTypes.func,
+ onComponentOptionChanged: PropTypes.func,
+ darkMode: PropTypes.bool,
+ styles: PropTypes.object,
+ properties: PropTypes.object,
+ setExposedVariable: PropTypes.func,
+ setExposedVariables: PropTypes.func,
+ dataCy: PropTypes.string,
+};
+
+FilePicker.defaultProps = {
+ width: '100%',
+ darkMode: false,
+ styles: {},
+ properties: {},
+ fireEvent: () => { },
+ setExposedVariable: () => { },
+ setExposedVariables: () => { },
+};
+
+export default FilePicker;
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/helpers/fileProcessing.js b/frontend/src/AppBuilder/Widgets/FilePicker/helpers/fileProcessing.js
new file mode 100644
index 0000000000..64ae5cacac
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/helpers/fileProcessing.js
@@ -0,0 +1,142 @@
+import * as XLSX from 'xlsx/xlsx.mjs';
+import { toast } from 'react-hot-toast';
+import JSON5 from 'json5'; // Import JSON5 for more lenient parsing
+
+// Define constants for processing file types
+// (Consider moving these to a shared constants file if used elsewhere)
+export const PARSE_FILE_TYPES = {
+ CSV: 'text/csv',
+ XLS: 'application/vnd.ms-excel',
+ XLSX: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ JSON: 'application/json', // Added JSON MIME type
+};
+
+// Helper functions for processing file content
+export const processCSV = (str, delimiter = ',') => {
+ try {
+ const wb = XLSX.read(str, { type: 'string', raw: true });
+ const wsname = wb.SheetNames[0];
+ const ws = wb.Sheets[wsname];
+ return XLSX.utils.sheet_to_json(ws, { delimiter, defval: '' });
+ } catch (error) {
+ console.error('Error processing CSV:', error);
+ toast.error('Failed to parse CSV file.');
+ return null;
+ }
+};
+
+export const processXls = (base64Str) => {
+ try {
+ const wb = XLSX.read(base64Str, { type: 'base64' });
+ const result = {};
+ // Iterate over all sheet names
+ wb.SheetNames.forEach((sheetName) => {
+ const ws = wb.Sheets[sheetName];
+ // Convert sheet to JSON array
+ const data = XLSX.utils.sheet_to_json(ws, { defval: '' }); // Use defval for empty cells
+ result[sheetName] = data; // Assign array to sheet name key
+ });
+ return result; // Return object with sheet names as keys
+ } catch (error) {
+ console.error('Error processing XLS/XLSX:', error);
+ toast.error('Failed to parse Excel file.');
+ return null;
+ }
+};
+
+// Added function to parse JSON content
+export const processJson = (str) => {
+ try {
+ // Use JSON5 for more flexibility (comments, trailing commas, etc.)
+ return JSON5.parse(str);
+ } catch (error) {
+ console.error('Error processing JSON:', error);
+ toast.error(`Failed to parse JSON file: ${error.message}`);
+ return null;
+ }
+};
+
+export const processFileContent = (fileType, fileContent) => {
+ switch (fileType) {
+ case PARSE_FILE_TYPES.CSV:
+ return processCSV(fileContent.readFileAsText);
+ case PARSE_FILE_TYPES.XLS:
+ case PARSE_FILE_TYPES.XLSX:
+ return processXls(fileContent.readFileAsDataURL); // Assuming this contains base64
+ case PARSE_FILE_TYPES.JSON:
+ return processJson(fileContent.readFileAsText); // Added JSON processing case
+ default:
+ console.warn(`Unsupported file type for parsing: ${fileType}`);
+ return null;
+ }
+};
+
+//? handle bad data in csv parser (e.g. empty cells) OR errors
+const DEPRECATED_handleErrors = (data) => {
+ const badData = data.filter((row) => {
+ return Object.values(row).some((value) => value === '');
+ });
+
+ const errors = data.filter((row) => {
+ return Object.values(row).some((value) => value === 'ERROR');
+ });
+
+ return [badData, errors];
+};
+
+const DEPRECATED_processCSV = (str, delimiter = ',') => {
+ try {
+ const wb = XLSX.read(str, { type: 'string', raw: true });
+ const wsname = wb.SheetNames[0];
+ const ws = wb.Sheets[wsname];
+ const data = XLSX.utils.sheet_to_json(ws, { delimiter, defval: '' });
+ return data;
+ } catch (error) {
+ console.log(error);
+ DEPRECATED_handleErrors(error);
+ }
+};
+
+const DEPRECATED_processXls = (str) => {
+ try {
+ const wb = XLSX.read(str, { type: 'base64' });
+ const wsname = wb.SheetNames[0];
+ const ws = wb.Sheets[wsname];
+ /* Convert array of arrays */
+ const data = XLSX.utils.sheet_to_json(ws);
+ return data;
+ } catch (error) {
+ console.log(error);
+ DEPRECATED_handleErrors(error);
+ }
+};
+
+export const DEPRECATED_processFileContent = (fileType, fileContent) => {
+ switch (fileType) {
+ case 'text/csv':
+ return DEPRECATED_processCSV(fileContent.readFileAsText);
+ case 'application/vnd.ms-excel':
+ case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
+ return DEPRECATED_processXls(fileContent.readFileAsDataURL);
+
+ default:
+ break;
+ }
+};
+
+export const detectParserFile = (file) => {
+ return Object.values(PARSE_FILE_TYPES).includes(file.type);
+};
+
+export const parseFileContentEnabled = (file, autoDetect = false, parseFileType) => {
+ // const fileExtensionType = file.type.split('/')[1]; // Simplified extraction - not strictly needed here
+
+ if (autoDetect) {
+ return detectParserFile(file);
+ } else {
+ // Map friendly name (like 'csv') to mime type if necessary
+ // Assumes parseFileType is like 'CSV', 'XLS', etc.
+ const targetMimeType = PARSE_FILE_TYPES[parseFileType?.toUpperCase()];
+ return targetMimeType ? file.type === targetMimeType : false;
+ }
+};
\ No newline at end of file
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/hooks/useFilePicker.js b/frontend/src/AppBuilder/Widgets/FilePicker/hooks/useFilePicker.js
new file mode 100644
index 0000000000..5344cee09c
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/hooks/useFilePicker.js
@@ -0,0 +1,596 @@
+import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
+import { useDropzone } from 'react-dropzone';
+import { toast } from 'react-hot-toast';
+import { formatFileSize } from '@/_helpers/utils';
+import { processFileContent, DEPRECATED_processFileContent, parseFileContentEnabled } from '../helpers/fileProcessing';
+import { useExposeState } from '@/AppBuilder/_hooks/useExposeVariables';
+
+export const useFilePicker = ({
+ validation,
+ properties,
+ styles,
+ fireEvent,
+ setExposedVariable,
+ setExposedVariables,
+ darkMode,
+ height,
+ id, // id might be needed for events
+ component, // component might be needed for events
+}) => {
+ const isInitialRender = useRef(true);
+
+ // --- Resolved Properties ---
+ const instructionText = properties?.instructionText ?? 'Drag and drop files here or click to select files';
+ const enableDropzone = properties?.enableDropzone ?? true;
+ const enablePicker = properties?.enablePicker ?? true;
+ const enableMultiple = properties?.enableMultiple ?? false;
+ const parseContent = properties.parseContent ?? false;
+ const fileTypeFromExtension = properties.parseFileType ?? 'auto-detect';
+ const labelText = properties.label ?? '';
+
+ const initialLoading = properties.loadingState ?? false;
+ const initialVisible = properties.visibility ?? true;
+ const initialDisabled = properties.disabledState ?? false;
+
+ const maxFileCount = validation?.maxFileCount ?? 2;
+ const fileTypeCategory = validation?.fileType ?? '*/*';
+ const maxSize = validation?.maxSize ?? 51200000;
+ const minSize = validation?.minSize ?? 50;
+ const minFileCount = validation?.minFileCount ?? 0;
+ const isMandatory = validation?.enableValidation ?? false;
+
+ // --- Resolved Styles ---
+ const containerBackgroundColor = styles?.containerBackgroundColor ?? 'var(--color-surface-1)';
+ const containerBorder = styles?.containerBorder ?? 'transparent';
+ const containerBoxShadow = styles?.containerBoxShadow ?? 'none';
+ const containerPadding = styles?.containerPadding ?? 16;
+ const borderRadius = styles?.borderRadius ?? 8;
+
+ const dropzoneTitleColor = styles?.dropzoneTitleColor ?? 'var(--text-primary';
+ const dropzoneActiveColor = styles?.dropzoneActiveColor ?? 'var(--primary-brand)';
+ const dropzoneErrorColor = styles?.dropzoneErrorColor ?? 'var(--status-error-strong)';
+ // --- Use useExposeState Hook ---
+ const { isDisabled, isVisible, isLoading } = useExposeState(
+ initialLoading,
+ initialVisible,
+ initialDisabled,
+ setExposedVariables,
+ setExposedVariable
+ );
+
+ // --- State ---
+ const [selectedFiles, setSelectedFiles] = useState([]);
+ const [fileErrors, setFileErrors] = useState({});
+ const [uploadingStatus, setUploadingStatus] = useState({});
+ const [isParsing, setIsParsing] = useState(false);
+ const [disablePicker, setDisablePicker] = useState(false);
+ const [isMinCountMet, setIsMinCountMet] = useState(true);
+ const [isMandatoryMet, setIsMandatoryMet] = useState(!isMandatory);
+ const [isValid, setIsValid] = useState(!isMandatory);
+ const [dropzoneRejections, setDropzoneRejections] = useState([]);
+ const [uiErrorMessage, setUiErrorMessage] = useState('');
+ const [isTouched, setIsTouched] = useState(false);
+
+ // Calculate total file size
+ const totalFileSize = useMemo(() => {
+ return selectedFiles.reduce((sum, file) => sum + (file.size || 0), 0);
+ }, [selectedFiles]);
+
+ // --- File Handling Logic ---
+ const getFileData = useCallback((file, method = 'readAsText') => {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onload = (event) => resolve(event.target.result);
+ reader.onerror = (error) => {
+ console.error('FileReader Error:', error);
+ if (error.name === 'NotReadableError') {
+ toast.error(error.message);
+ }
+ reject(error);
+ };
+ if (method === 'readAsDataURL') {
+ reader.readAsDataURL(file);
+ } else {
+ reader.readAsText(file);
+ }
+ });
+ }, []);
+
+ const fileReader = useCallback(
+ async (file) => {
+ try {
+ const readFileAsText = await getFileData(file, 'readAsText');
+ const readFileAsDataURLResult = await getFileData(file, 'readAsDataURL');
+ const base64Data = readFileAsDataURLResult.split(',')[1];
+
+ const shouldProcessFileParsing =
+ parseContent && parseFileContentEnabled(file, fileTypeFromExtension === 'auto-detect', fileTypeFromExtension);
+
+ let parsedValue = null;
+ let parsedData = null;
+ if (shouldProcessFileParsing) {
+ const contentForParsing = {
+ readFileAsText: readFileAsText,
+ readFileAsDataURL: base64Data,
+ };
+ parsedValue = processFileContent(file.type, contentForParsing);
+ parsedData = DEPRECATED_processFileContent(file.type, contentForParsing);
+ }
+
+ return {
+ lastModified: file.lastModified,
+ lastModifiedDate: file.lastModifiedDate,
+ name: file.name,
+ size: file.size,
+ type: file.type,
+ webkitRelativePath: file.webkitRelativePath,
+ content: readFileAsText,
+ base64Data: base64Data,
+ parsedValue: parsedValue,
+ parsedData: parsedData,
+ };
+ } catch (error) {
+ console.error(`Error reading file ${file.name}:`, error);
+ // Update status/errors directly here or ensure it's handled by caller
+ setUploadingStatus((prev) => ({ ...prev, [file.name]: 'error' }));
+ setFileErrors((prev) => ({
+ ...prev,
+ [file.name]: error.message || 'Failed to read file',
+ }));
+ throw error; // Re-throw for Promise.allSettled
+ }
+ },
+ [getFileData, parseContent, fileTypeFromExtension]
+ );
+
+ // --- Dropzone Setup ---
+ const onDropRejected = useCallback(
+ (rejectedFiles) => {
+ // For UI display, decide on one message
+ if (rejectedFiles.length === 1) {
+ const { file, errors } = rejectedFiles[0];
+ const error = errors[0];
+ let specificMessage = error.message;
+ // Generate specific message (similar to existing logic but for a single error)
+ switch (error.code) {
+ case 'file-invalid-type':
+ specificMessage = `The file "${file.name}" has an unsupported file type.`;
+ if (fileTypeCategory && fileTypeCategory !== '*/*') {
+ specificMessage += ` Please upload files of type: ${fileTypeCategory}.`;
+ }
+ break;
+ case 'file-too-small':
+ specificMessage = `The file "${file.name}" (${formatFileSize(
+ file.size
+ )}) is smaller than the minimum allowed size of ${formatFileSize(minSize)}.`;
+ break;
+ case 'file-too-large':
+ specificMessage = `The file "${file.name}" (${formatFileSize(
+ file.size
+ )}) exceeds the maximum allowed size of ${formatFileSize(maxSize)}.`;
+ break;
+ case 'too-many-files':
+ specificMessage = `You can select a maximum of ${maxFileCount} files.`;
+ break;
+ case 'duplicate-file':
+ specificMessage = `The file "${file.name}" has already been selected.`;
+ break;
+ default:
+ specificMessage =
+ error.message && typeof error.message === 'string' && error.message.trim() !== ''
+ ? error.message
+ : `An issue occurred with file "${file.name}".`;
+ break;
+ }
+ setUiErrorMessage(specificMessage);
+ toast.error(specificMessage); // Toast the specific error
+ } else if (rejectedFiles.length > 1) {
+ const genericMessage = 'Multiple files have errors. Please check the requirements.';
+ setUiErrorMessage(genericMessage);
+ // Toast individual errors if desired, or one generic toast
+ for (const { file, errors } of rejectedFiles) {
+ // Simplified toast for multiple errors, could be more detailed
+ toast.error(`Error with ${file.name}: ${errors[0].message}`);
+ }
+ }
+ // dropzoneRejections state can be kept raw for other potential uses or removed if only for this UI message
+ setDropzoneRejections(rejectedFiles); // Keep raw rejections for potential debugging or detailed listing elsewhere
+
+ // Clear setUiErrorMessage afgter 5 seconds
+ setTimeout(() => {
+ clearErrorStates();
+ }, 10000);
+ },
+ [fileTypeCategory, minSize, maxSize, maxFileCount]
+ );
+
+ // Custom validator
+ const validateFile = useCallback(
+ (file) => {
+ // Check 1: Duplicate file
+ if (selectedFiles.some((existingFile) => existingFile.name === file.name && existingFile.size === file.size)) {
+ return {
+ code: 'duplicate-file',
+ message: `The file "${file.name}" has already been selected.`,
+ };
+ }
+
+ // Check 2: If single file mode and a file is already selected
+ if (!enableMultiple && selectedFiles.length >= 1) {
+ return {
+ code: 'max-files-exceeded',
+ message: 'Only one file can be uploaded.',
+ };
+ }
+
+ // Check 3: If multiple file mode and max file count is already reached
+ if (enableMultiple && selectedFiles.length >= maxFileCount) {
+ return {
+ code: 'max-files-exceeded',
+ message: `You can only upload up to ${maxFileCount} files.`,
+ };
+ }
+
+ return null; // File passes custom validation
+ },
+ [selectedFiles, enableMultiple, maxFileCount]
+ );
+
+ const onDrop = useCallback(
+ async (acceptedDropFiles) => {
+ // Fire 'onFileSelected' event before processing
+ fireEvent?.('onFileSelected');
+ setIsTouched(true); // Set touched state
+
+ const currentFileNames = selectedFiles.map((f) => f.name);
+ const newFilesToAdd = acceptedDropFiles.filter((f) => !currentFileNames.includes(f.name));
+
+ if (parseContent) {
+ setIsParsing(true);
+ setExposedVariable?.('isParsing', true);
+ }
+
+ const processPromises = newFilesToAdd.map((file) => {
+ setUploadingStatus((prev) => ({ ...prev, [file.name]: 'uploading' }));
+ return fileReader(file);
+ });
+
+ const results = await Promise.allSettled(processPromises);
+
+ const successfullyProcessedFiles = [];
+ const currentErrors = { ...fileErrors }; // Use a local copy for this drop operation
+ const currentStatuses = { ...uploadingStatus };
+
+ results.forEach((result, index) => {
+ const fileName = newFilesToAdd[index].name;
+ if (result.status === 'fulfilled') {
+ successfullyProcessedFiles.push(result.value);
+ currentStatuses[fileName] = 'uploaded';
+ if (currentErrors[fileName]) delete currentErrors[fileName]; // Clear previous error
+ } else {
+ const errorMsg = result.reason?.message || 'Failed to process file';
+ currentErrors[fileName] = errorMsg;
+ currentStatuses[fileName] = 'error';
+ toast.error(`Error processing ${fileName}: ${errorMsg}`);
+ }
+ });
+
+ setSelectedFiles((prevFiles) => {
+ const updatedFiles = enableMultiple
+ ? [...prevFiles, ...successfullyProcessedFiles]
+ : [...successfullyProcessedFiles];
+ return enableMultiple ? updatedFiles.slice(0, maxFileCount) : updatedFiles;
+ });
+
+ setFileErrors(currentErrors); // Update state with errors from this drop
+ setUploadingStatus(currentStatuses); // Update state with statuses from this drop
+
+ if (parseContent) {
+ setIsParsing(false);
+ setExposedVariable?.('isParsing', false);
+ }
+
+ // Fire 'onFileLoaded' event after processing
+ if (fireEvent && successfullyProcessedFiles.length > 0) {
+ fireEvent?.('onFileLoaded', { files: successfullyProcessedFiles });
+ }
+
+ // Clear dropzone rejections when new files are accepted
+ if (acceptedDropFiles.length > 0) {
+ setDropzoneRejections([]);
+ }
+ },
+ [
+ selectedFiles,
+ parseContent,
+ fireEvent,
+ setExposedVariable,
+ fileReader,
+ enableMultiple,
+ maxFileCount,
+ fileErrors,
+ uploadingStatus,
+ ]
+ );
+
+ // Calculate the accept prop based on the category
+ const acceptProp = useMemo(() => {
+ const pattern = fileTypeCategory;
+ if (!pattern) {
+ return null; // Accept all if pattern is null/undefined or category not found
+ }
+ // Convert comma-separated string to the object format react-dropzone expects
+ return pattern.split(',').reduce((acc, type) => {
+ const trimmedType = type.trim();
+ if (trimmedType) acc[trimmedType] = [];
+ return acc;
+ }, {});
+ }, [fileTypeCategory]);
+
+ // Reusable function to clear error states
+ const clearErrorStates = useCallback(() => {
+ setUiErrorMessage('');
+ setDropzoneRejections([]);
+ setFileErrors({});
+ setUploadingStatus({});
+ }, []);
+
+ const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
+ accept: acceptProp, // Use the calculated accept prop
+ noClick: !enablePicker || disablePicker,
+ noDrag: !enableDropzone || disablePicker,
+ noKeyboard: true,
+ maxSize: maxSize,
+ minSize: minSize,
+ multiple: enableMultiple,
+ disabled: isDisabled || disablePicker,
+ onDropRejected: onDropRejected,
+ validator: validateFile,
+ onDrop: onDrop,
+ onDropAccepted: (acceptedFiles) => {
+ // After files are accepted, check if minFileCount is met
+ if (selectedFiles.length + acceptedFiles.length < minFileCount) {
+ setUiErrorMessage(`Please select at least ${minFileCount} file${minFileCount > 1 ? 's' : ''}.`);
+ setTimeout(() => {
+ clearErrorStates();
+ }, 5000);
+ } else {
+ setUiErrorMessage('');
+ }
+ },
+ onFileDialogOpen: () => {
+ clearErrorStates();
+ setTimeout(() => {
+ setIsTouched(true); // Set touched state
+ }, 2000);
+ },
+ });
+
+ // Function to remove a file
+ const handleRemoveFile = useCallback(
+ (indexToRemove) => {
+ const fileToRemove = selectedFiles[indexToRemove];
+ if (!fileToRemove) return;
+
+ setSelectedFiles((prevFiles) => prevFiles.filter((_, index) => index !== indexToRemove));
+
+ setFileErrors((prev) => {
+ const newErrors = { ...prev };
+ delete newErrors[fileToRemove.name];
+ return newErrors;
+ });
+ setUploadingStatus((prev) => {
+ const newStatus = { ...prev };
+ delete newStatus[fileToRemove.name];
+ return newStatus;
+ });
+
+ fireEvent?.('onFileDeselected', { file: fileToRemove });
+ },
+ [selectedFiles, fireEvent]
+ );
+
+ // --- Exposed Actions ---
+ const clearFiles = useCallback(() => {
+ setSelectedFiles([]);
+ setFileErrors({});
+ setUploadingStatus({});
+ }, []);
+
+ const setFileName = useCallback(
+ (indexOrUpdates, newNameIfSingle) => {
+ setSelectedFiles((currentFiles) => {
+ const updateMap = {}; // Changed from let to const
+ if (Array.isArray(indexOrUpdates)) {
+ // Batch update: [{index: number, newFileName: string}]
+ for (const update of indexOrUpdates) {
+ if (typeof update.index === 'number' && typeof update.newFileName === 'string') {
+ updateMap[update.index] = update.newFileName.trim();
+ }
+ }
+ } else if (typeof indexOrUpdates === 'number' && typeof newNameIfSingle === 'string') {
+ // Single update: (index: number, newFileName: string)
+ const index = indexOrUpdates;
+ const newFileName = newNameIfSingle.trim();
+ if (newFileName !== '') {
+ updateMap[index] = newFileName;
+ }
+ }
+
+ if (Object.keys(updateMap).length === 0) return currentFiles; // No valid updates
+
+ return currentFiles.map((file, index) => {
+ if (Object.prototype.hasOwnProperty.call(updateMap, index)) {
+ const newNameBase = updateMap[index];
+ const currentNameParts = file.name.split('.');
+ const extension = currentNameParts.length > 1 ? currentNameParts.pop() : null;
+ const finalNewName = extension ? `${newNameBase}.${extension}` : newNameBase;
+ // Ensure name doesn't become empty if base is empty and no extension
+ if (finalNewName === '' || finalNewName === '.') return file;
+ return { ...file, name: finalNewName };
+ }
+ return file;
+ });
+ });
+ },
+ [] // No dependencies needed
+ );
+
+ // --- Effects ---
+ useEffect(() => {
+ const newIsMandatoryMet = !isMandatory || selectedFiles.length > 0;
+ setIsMandatoryMet(newIsMandatoryMet);
+
+ const newIsMinCountMet = selectedFiles.length >= minFileCount || !enableMultiple;
+ setIsMinCountMet(newIsMinCountMet);
+
+ const newIsValid = newIsMandatoryMet && newIsMinCountMet;
+ setIsValid(newIsValid);
+
+ // Update exposed validation status
+ setExposedVariable?.('isValid', newIsValid);
+
+ if (isMandatory && selectedFiles.length === 0 && isTouched && !isDragActive) {
+ setUiErrorMessage('This field is mandatory. Please select a file.');
+ } else if (
+ uiErrorMessage === 'This field is mandatory. Please select a file.' &&
+ (selectedFiles.length > 0 || !isMandatory || !isTouched || isDragActive)
+ ) {
+ setUiErrorMessage('');
+ }
+ }, [
+ selectedFiles.length,
+ isMandatory,
+ isTouched,
+ uiErrorMessage,
+ isDragActive,
+ setUiErrorMessage,
+ minFileCount,
+ enableMultiple,
+ setExposedVariable,
+ ]);
+
+ useEffect(() => {
+ // Update exposed variables
+ if (!isInitialRender.current) {
+ const minMet = selectedFiles.length >= minFileCount;
+ const mandatoryMet = !isMandatory || selectedFiles.length > 0;
+ const currentIsValid = minMet && mandatoryMet;
+
+ setIsMinCountMet(minMet);
+ setIsMandatoryMet(mandatoryMet);
+ setIsValid(currentIsValid);
+
+ // useExposeState handles: isLoading, isVisible, isDisabled, setVisibility, setLoading, setDisable
+ // We manually expose widget-specific items:
+ setExposedVariables?.({
+ clearFiles: clearFiles,
+ setFileName: setFileName,
+ });
+ setExposedVariable?.('files', selectedFiles); // Contains parsedValue
+ setExposedVariable?.('file', selectedFiles); // Contains parsedValue
+ setExposedVariable?.('isParsing', isParsing);
+ setExposedVariable?.('isMandatory', isMandatory);
+ setExposedVariable?.('isValid', currentIsValid);
+ setExposedVariable?.('fileSize', totalFileSize);
+ setExposedVariable?.('uiErrorMessage', uiErrorMessage);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [
+ selectedFiles,
+ isParsing,
+ minFileCount,
+ isMandatory,
+ totalFileSize,
+ clearFiles,
+ setFileName,
+ setExposedVariables,
+ setExposedVariable,
+ uiErrorMessage,
+ dropzoneRejections,
+ ]); // Multi-line dependencies
+
+ useEffect(() => {
+ // Initial setup only
+ const initialIsValid = !isMandatory; // Calculate initial validity here
+ // useExposeState handles initial exposure of common vars/setters
+ // We manually expose widget-specific items initially:
+ setExposedVariables?.({
+ clearFiles: clearFiles,
+ setFileName: setFileName,
+ });
+ setExposedVariable?.('files', []);
+ setExposedVariable?.('file', []);
+ setExposedVariable?.('isParsing', false);
+ setExposedVariable?.('isMandatory', isMandatory);
+ setExposedVariable?.('isValid', initialIsValid);
+ setExposedVariable?.('fileSize', 0);
+ setExposedVariable?.('uiErrorMessage', '');
+
+ setIsMandatoryMet(!isMandatory);
+ setIsValid(initialIsValid); // Set initial state using the calculated value
+ isInitialRender.current = false;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isMandatory, clearFiles, setFileName, setExposedVariables, setExposedVariable]); // Multi-line dependencies
+
+ useEffect(() => {
+ // Update internal disablePicker based on isDisabled from useExposeState and other logic
+ const shouldDisable =
+ isDisabled || // Use isDisabled from hook
+ (enableMultiple && selectedFiles.length >= maxFileCount) ||
+ (!enableMultiple && selectedFiles.length >= 1);
+ setDisablePicker(shouldDisable);
+ // Use isDisabled from useExposeState for dropzone disabled prop
+ }, [selectedFiles.length, maxFileCount, enableMultiple, isDisabled]);
+
+ useEffect(() => {
+ // Clear UI error message when isDisabled state changes
+ setUiErrorMessage('');
+ }, [isDisabled, setUiErrorMessage]);
+
+ // --- Styles for Dropzone ---
+ // Moved style calculation to component as it depends on drag states from useDropzone return
+
+ return {
+ isVisible,
+ isLoading,
+ // Dropzone props
+ getRootProps,
+ getInputProps,
+ isDragActive,
+ isDragAccept,
+ isDragReject,
+ // File state
+ selectedFiles,
+ fileErrors,
+ uploadingStatus,
+ dropzoneRejections,
+ isParsing,
+ // Actions
+ handleRemoveFile,
+ // Calculated state/props for component
+ labelText,
+ instructionText,
+ disablePicker, // Needed for styling/cursor
+ disabledState: isDisabled, // Return isDisabled from useExposeState
+ borderRadius, // Needed for styling
+ containerBackgroundColor,
+ containerBorder,
+ containerBoxShadow,
+ containerPadding,
+ dropzoneTitleColor,
+ dropzoneActiveColor,
+ dropzoneErrorColor,
+ height, // Needed for styling
+ minSize,
+ maxSize,
+ isMandatory,
+ minFileCount,
+ maxFileCount,
+ isMinCountMet,
+ isMandatoryMet,
+ clearFiles, // Return actions if needed internally (currently not)
+ setFileName, // Return actions if needed internally (currently not)
+ uiErrorMessage, // Return new state
+ };
+};
diff --git a/frontend/src/AppBuilder/Widgets/FilePicker/style.scss b/frontend/src/AppBuilder/Widgets/FilePicker/style.scss
new file mode 100644
index 0000000000..63c9ac1a78
--- /dev/null
+++ b/frontend/src/AppBuilder/Widgets/FilePicker/style.scss
@@ -0,0 +1,291 @@
+:root {
+ --file-picker-primary-brand: var(--primary-brand);
+ --file-picker-error-strong: var(--status-error-strong);
+ --file-picker-text-primary: var(--text-primary);
+ --file-picker-border-radius: 6px;
+ --file-picker-background-color: var(--color-surface-1);
+ --file-picker-border: transparent;
+ --file-picker-box-shadow: none;
+ --file-picker-padding: 16px;
+}
+
+// File List Item
+.file-list-item {
+ width: 100%;
+ min-width: 0;
+ height: 32px;
+ border-radius: 8px;
+ padding: 0 10px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ background: var(--surfaces-surface-01);
+ border: 1px solid transparent;
+ box-sizing: border-box;
+ color: var(--cc-primary-text);
+
+ &:hover {
+ background: var(--surfaces-surface-02);
+
+ .delete-button {
+ opacity: 1;
+ visibility: visible;
+ }
+ }
+
+ &.error {
+ .file-error-message {
+ color: var(--status-error-strong);
+ }
+ }
+
+ &.uploading {
+ opacity: 0.7;
+ }
+
+ .file-details {
+ display: flex;
+ align-items: end;
+ gap: 4px;
+ flex-grow: 1;
+ overflow: hidden;
+
+ .file-name {
+ font-weight: 500;
+ color: var(--file-picker-text-primary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .file-meta {
+ color: var(--cc-placeholder-text);
+ font-size: 11px;
+ white-space: nowrap;
+ }
+ }
+
+ .delete-button {
+ width: 20px;
+ flex-shrink: 0;
+ padding: 0;
+ opacity: 0;
+ visibility: hidden;
+ background-color: var(--cc-surface1-surface);
+ border-color: var(--cc-default-border);
+
+ &:hover {
+ background-color: var(--file-picker-delete-button-hover-bg) !important;
+ }
+ }
+}
+
+// File Picker Dropzone
+.file-picker-dropzone {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--file-picker-padding);
+ border: 1px dashed var(--cc-default-border);
+ outline: none;
+ border-radius: var(--file-picker-border-radius);
+ transition-property: border-color, background-color, box-shadow, color;
+ transition-duration: 0.18s;
+ transition-timing-function: ease-in-out;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+ min-height: 52px;
+ cursor: pointer;
+ margin-top: 0.5rem;
+
+ &:hover {
+ border-color: var(--cc-primary-brand);
+ color: var(--cc-primary-text);
+ border-width: 2px;
+ }
+
+ &:focus,
+ &:active {
+ border-color: var(--cc-primary-brand);
+ color: var(--cc-primary-text);
+ }
+
+ &.is-dragging {
+ border-color: var(--cc-primary-brand);
+ border-width: 2px;
+ }
+
+ &.is-accepting {
+ border-color: var(--cc-primary-brand);
+ border-width: 2px;
+ }
+
+ &.is-rejecting {
+ border-color: var(--status-error-strong);
+ }
+
+ &.is-focused {
+ // border-style: solid;
+ // border-color: var(--primary-accent-strong);
+ box-shadow: 0 0 0 2px var(--surfaces-surface-01),
+ 0 0 0 4px var(--interactive-overlays-focus-outline);
+ }
+
+ &.is-disabled {
+ background-color: var(--cc-surface2-surface);
+ cursor: not-allowed;
+ opacity: 0.6;
+ }
+
+ .dropzone {
+
+ &-instruction,
+ &-message {
+ text-align: center;
+ margin: 0;
+ font-size: 14px;
+ line-height: 20px;
+ }
+
+ &-instruction-link {
+ color: var(--cc-primary-brand);
+ font-weight: 500;
+ cursor: pointer;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+}
+
+// Validation Bar
+.validation-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ box-sizing: border-box;
+ color: var(--text-placeholder);
+ font-weight: 400;
+ font-size: 12px;
+ line-height: 20px;
+ letter-spacing: 0;
+
+ .validation-info {
+ color: var(--cc-placeholder-text);
+ }
+
+ .validation-separator {
+ margin: 0 8px;
+ color: var(--borders-default);
+ }
+}
+
+// File Picker Widget
+.file-picker {
+ &-title {
+ color: var(--cc-primary-text);
+ text-align: left;
+ width: 100%;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 20px;
+ letter-spacing: 0;
+ margin: 0;
+ }
+
+ &-widget-wrapper {
+ // padding: var(--file-picker-padding);
+ display: flex;
+ flex-direction: column;
+ // gap: 12px;
+ background-color: var(--file-picker-background-color);
+ border-radius: var(--file-picker-border-radius);
+ border: var(--file-picker-border);
+ box-shadow: var(--file-picker-box-shadow);
+ }
+
+ &-files-pane {
+ margin: 0;
+ min-height: 0;
+ padding: 0 0.75rem;
+ padding-top: 0.5rem;
+ display: flex;
+ flex-direction: column;
+
+ &:only-child {
+ height: auto;
+ }
+ }
+}
+
+.file-list-container {
+ display: grid;
+ grid-template-columns: 1fr;
+ width: 100%;
+ height: auto;
+}
+
+// Error Message
+.file-picker-error-message {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ margin-bottom: 0;
+ color: var(--status-error-strong);
+
+ .error-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ color: var(--status-error-strong);
+ }
+
+ .error-text {
+ font-size: 14px;
+ line-height: 20px;
+ color: var(--status-error-strong);
+ }
+}
+
+.files-pane-scrollable {
+ overflow-y: auto;
+
+ scrollbar-width: thin;
+ scrollbar-color: transparent transparent;
+ height: 100%;
+ overflow: hidden auto;
+
+ /* Hide scrollbar by default */
+ &::-webkit-scrollbar {
+ width: 6px;
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: transparent;
+ }
+
+ /* Show scrollbar only on hover */
+ &:hover {
+ &::-webkit-scrollbar-thumb {
+ background-color: #6a727c4d;
+ border-radius: 3px;
+ }
+ }
+
+ &:hover {
+ scrollbar-color: #6a727c4d transparent;
+ }
+}
+
+.files-pane-auto-height {
+ height: auto;
+ overflow-y: visible;
+}
\ No newline at end of file
diff --git a/frontend/src/AppBuilder/Widgets/Form/Components/HorizontalSlot.jsx b/frontend/src/AppBuilder/Widgets/Form/Components/HorizontalSlot.jsx
index 888b91d3b7..7e73239e96 100644
--- a/frontend/src/AppBuilder/Widgets/Form/Components/HorizontalSlot.jsx
+++ b/frontend/src/AppBuilder/Widgets/Form/Components/HorizontalSlot.jsx
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react';
import { Container as SubContainer } from '@/AppBuilder/AppCanvas/Container';
-import { showGridLinesOnSlot, hideGridLinesOnSlot } from '@/AppBuilder/AppCanvas/Grid/gridUtils';
-import { useResizable } from '@/AppBuilder/_hooks/useMoveable';
+import { showGridLines, hideGridLines } from '@/AppBuilder/AppCanvas/Grid/gridUtils';
+import { useSubContainerResizable } from '@/AppBuilder/_hooks/useSubContainerResizable';
export const HorizontalSlot = React.memo(
({
@@ -16,10 +16,10 @@ export const HorizontalSlot = React.memo(
onResize,
isEditing,
maxHeight,
+ componentType,
}) => {
const parsedHeight = parseInt(height, 10);
-
- const { getRootProps, getHandleProps, getResizeState } = useResizable({
+ const { getRootProps, getHandleProps, getResizeState } = useSubContainerResizable({
initialHeight: parsedHeight,
initialWidth: '100%', // Now respects parent's width
minHeight: 10,
@@ -34,12 +34,11 @@ export const HorizontalSlot = React.memo(
});
const { height: resizedHeight, isDragging } = getResizeState();
-
useEffect(() => {
if (isDragging) {
- showGridLinesOnSlot(id);
+ showGridLines();
} else {
- hideGridLinesOnSlot(id);
+ hideGridLines();
}
}, [isDragging, id]);
@@ -50,7 +49,10 @@ export const HorizontalSlot = React.memo(
};
return (
-
+
diff --git a/frontend/src/AppBuilder/Widgets/Form/Form.jsx b/frontend/src/AppBuilder/Widgets/Form/Form.jsx
index 02b2573484..a8da234352 100644
--- a/frontend/src/AppBuilder/Widgets/Form/Form.jsx
+++ b/frontend/src/AppBuilder/Widgets/Form/Form.jsx
@@ -5,6 +5,8 @@ import _, { debounce, omit } from 'lodash';
import { generateUIComponents, getBodyHeight } from './FormUtils';
import { useMounted } from '@/_hooks/use-mount';
import { onComponentClick, removeFunctionObjects } from '@/_helpers/appUtils';
+import { useAppInfo } from '@/_stores/appDataStore';
+import { useDynamicHeight } from '@/_hooks/useDynamicHeight';
import { deepClone } from '@/_helpers/utilities/utils.helpers';
import RenderSchema from './RenderSchema';
import useStore from '@/AppBuilder/_stores/store';
@@ -16,10 +18,14 @@ import {
} from '@/AppBuilder/AppCanvas/appCanvasConstants';
import { HorizontalSlot } from './Components/HorizontalSlot';
import { useActiveSlot } from '@/AppBuilder/_hooks/useActiveSlot';
+// eslint-disable-next-line import/no-unresolved
+import { diff } from 'deep-object-diff';
+import { checkDiff } from '@/AppBuilder/Widgets/componentUtils';
+import Spinner from '@/_ui/Spinner';
import './form.scss';
-export const Form = function Form(props) {
+const FormComponent = (props) => {
const {
id,
component,
@@ -33,20 +39,34 @@ export const Form = function Form(props) {
properties,
resetComponent = () => {},
dataCy,
+ adjustComponentPositions,
+ currentLayout,
+ componentCount,
onComponentClick,
} = props;
- const childComponents = useStore((state) => state.getChildComponents(id), shallow);
+ const childComponents = useStore((state) => state.getChildComponents(id), checkDiff);
+ const isJSONSchema = useStore((state) => state.isJsonSchemaInGenerateFormFrom(id), shallow);
+
const { borderRadius, borderColor, boxShadow, footerBackgroundColor, headerBackgroundColor } = styles;
+
const {
buttonToSubmit,
- advanced,
- JSONSchema,
+ advanced: _deprecatedAdvanced,
+ JSONSchema: _deprecatedJSONSchema,
showHeader = false,
showFooter = false,
headerHeight = 80,
footerHeight = 80,
canvasHeight,
+ validateOnSubmit = true,
+ resetOnSubmit = true,
+ newJsonSchema,
+ dynamicHeight,
} = properties;
+
+ const advanced = _deprecatedAdvanced || isJSONSchema;
+ const JSONSchema = _deprecatedAdvanced ? _deprecatedJSONSchema : newJsonSchema;
+
const { isDisabled, isVisible, isLoading } = useExposeState(
properties.loadingState,
properties.visibility,
@@ -64,7 +84,7 @@ export const Form = function Form(props) {
backgroundColor,
borderRadius: borderRadius ? parseFloat(borderRadius) : 0,
border: `${SUBCONTAINER_CANVAS_BORDER_WIDTH}px solid ${borderColor}`,
- height,
+ height: dynamicHeight ? '100%' : height,
display: isVisible ? 'flex' : 'none',
position: 'relative',
boxShadow,
@@ -75,13 +95,46 @@ export const Form = function Form(props) {
const formContent = {
overflow: 'hidden auto',
display: 'flex',
- height: '100%',
+ height: canHeight || '100%',
paddingTop: `${CONTAINER_FORM_CANVAS_PADDING}px`,
paddingBottom: showFooter ? '3px' : '7px',
paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`,
paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`,
};
+ const headerMaxHeight = parseInt(height, 10) - parseInt(footerHeight, 10) - 100 - 10;
+ const footerMaxHeight = parseInt(height, 10) - parseInt(headerHeight, 10) - 100 - 10;
+
+ const formFooter = {
+ flexShrink: 0,
+ paddingTop: '3px',
+ paddingBottom: '7px',
+ paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`,
+ paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`,
+ maxHeight: `${footerMaxHeight}px`,
+ backgroundColor:
+ ['#fff', '#ffffffff'].includes(footerBackgroundColor) && darkMode ? '#1F2837' : footerBackgroundColor,
+ };
+ const formHeader = {
+ flexShrink: 0,
+ paddingBottom: '3px',
+ paddingTop: '7px',
+ paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`,
+ paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`,
+ maxHeight: `${headerMaxHeight}px`,
+ backgroundColor:
+ ['#fff', '#ffffffff'].includes(headerBackgroundColor) && darkMode ? '#1F2837' : headerBackgroundColor,
+ };
+ useDynamicHeight({
+ dynamicHeight,
+ id,
+ height,
+ adjustComponentPositions,
+ currentLayout,
+ isContainer: true,
+ componentCount,
+ });
+
const parentRef = useRef(null);
const childDataRef = useRef({});
@@ -96,17 +149,18 @@ export const Form = function Form(props) {
resetComponent();
},
submitForm: async function () {
- if (isValid) {
- fireEvent('onSubmit').then(() => resetComponent());
- } else {
- fireEvent('onInvalid');
+ if (validateOnSubmit) {
+ if (!isValid) {
+ return fireEvent('onInvalid');
+ }
}
+ fireEvent('onSubmit').then(() => resetOnSubmit && resetComponent());
},
};
setExposedVariables(exposedVariables);
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ }, [resetOnSubmit, validateOnSubmit]);
const extractData = (data) => {
const result = {};
@@ -151,10 +205,13 @@ export const Form = function Form(props) {
useEffect(() => {
let formattedChildData = {};
let childValidation = true;
+ let formData = {}; // New object to store form data
+
if (!childComponents) {
const exposedVariables = {
data: formattedChildData,
isValid: childValidation,
+ formData, // Expose formData
...(!advanced && { children: formattedChildData }),
};
@@ -169,21 +226,39 @@ export const Form = function Form(props) {
Object.keys(childComponents ?? {}).forEach((childId) => {
if (childrenData?.[childId]?.name) {
const componentName = childComponents?.[childId]?.component?.component?.name;
+ const componentValue = (() => {
+ const childData = childrenData[childId];
+ if (!childData) return null; // Default to null if childData is undefined
+
+ if (childData.hasOwnProperty('value')) return childData.value;
+ if (childData.hasOwnProperty('values')) return childData.values;
+ if (childData.hasOwnProperty('file')) return childData.file;
+ if (childData.hasOwnProperty('selectedDateRange')) return childData.selectedDateRange;
+
+ return null; // Default to null if no matching key is found
+ })();
+
+ if (componentValue !== null) {
+ formData[componentName] = componentValue; // Populate formData
+ }
formattedChildData[componentName] = { ...omit(childrenData[childId], 'name'), id: childId };
childValidation = childValidation && (childrenData[childId]?.isValid ?? true);
}
});
}
+
formattedChildData = Object.fromEntries(
- // eslint-disable-next-line no-unused-vars
- Object.entries(formattedChildData).map(([key, { formKey, ...rest }]) => [key, rest]) // removing formkey from final exposed data
+ Object.entries(formattedChildData).map(([key, { formKey, ...rest }]) => [key, rest]) // removing formKey from final exposed data
);
+
const formattedChildDataClone = deepClone(formattedChildData);
const exposedVariables = {
...(!advanced && { children: formattedChildDataClone }),
data: removeFunctionObjects(formattedChildData),
isValid: childValidation,
+ formData, // Expose formData
};
+
setExposedVariables(exposedVariables);
setValidation(childValidation);
}, [childrenData, advanced]);
@@ -192,19 +267,22 @@ export const Form = function Form(props) {
document.addEventListener('submitForm', handleFormSubmission);
return () => document.removeEventListener('submitForm', handleFormSubmission);
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [buttonToSubmit, isValid, advanced, JSON.stringify(uiComponents)]);
+ }, [buttonToSubmit, isValid, advanced, JSON.stringify(uiComponents), resetOnSubmit, validateOnSubmit]);
const handleSubmit = (event) => {
event.preventDefault();
};
const fireSubmissionEvent = () => {
- if (isValid) {
- fireEvent('onSubmit').then(() => {
- debounce(() => resetComponent(), 100)();
- });
- } else {
- fireEvent('onInvalid');
+ if (validateOnSubmit) {
+ if (!isValid) {
+ return fireEvent('onInvalid');
+ }
}
+ fireEvent('onSubmit').then(() => {
+ if (resetOnSubmit) {
+ debounce(() => resetComponent(), 100)();
+ }
+ });
};
const handleFormSubmission = ({ detail: { buttonComponentId } }) => {
@@ -293,28 +371,6 @@ export const Form = function Form(props) {
const roundedHeight = Math.round(maxHeight / 10) * 10;
setCanHeight(`${roundedHeight}px`);
}, [computedFormBodyHeight, canvasHeight]);
- const headerMaxHeight = parseInt(height, 10) - parseInt(footerHeight, 10) - 100 - 10;
- const footerMaxHeight = parseInt(height, 10) - parseInt(headerHeight, 10) - 100 - 10;
- const formFooter = {
- flexShrink: 0,
- paddingTop: '3px',
- paddingBottom: '7px',
- paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`,
- paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`,
- maxHeight: `${footerMaxHeight}px`,
- backgroundColor:
- ['#fff', '#ffffffff'].includes(footerBackgroundColor) && darkMode ? '#1F2837' : footerBackgroundColor,
- };
- const formHeader = {
- flexShrink: 0,
- paddingBottom: '3px',
- paddingTop: '7px',
- paddingLeft: `${CONTAINER_FORM_CANVAS_PADDING}px`,
- paddingRight: `${CONTAINER_FORM_CANVAS_PADDING}px`,
- maxHeight: `${headerMaxHeight}px`,
- backgroundColor:
- ['#fff', '#ffffffff'].includes(headerBackgroundColor) && darkMode ? '#1F2837' : headerBackgroundColor,
- };
return (
)}
-
-
+
{isLoading ? (
) : (
-