Merge pull request #12591 from ToolJet/feat/steps-v2-alignment-style-improvement

feat: dynamic steps length based on steps text size
This commit is contained in:
Johnson Cherian 2025-05-15 15:28:29 +05:30 committed by GitHub
commit 31552242a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1650 additions and 468 deletions

View file

@ -0,0 +1,538 @@
import React, { useState, useEffect } from 'react';
import Accordion from '@/_ui/Accordion';
import { EventManager } from '../EventManager';
import { renderElement } from '../Utils';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Popover from 'react-bootstrap/Popover';
import List from '@/ToolJetUI/List/List';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
import useStore from '@/AppBuilder/_stores/store';
import CodeHinter from '@/AppBuilder/CodeEditor';
import AddNewButton from '@/ToolJetUI/Buttons/AddNewButton/AddNewButton';
import ListGroup from 'react-bootstrap/ListGroup';
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
import SortableList from '@/_components/SortableList';
import Trash from '@/_ui/Icon/solidIcons/Trash';
import { shallow } from 'zustand/shallow';
import Switch from '@/Editor/CodeBuilder/Elements/Switch';
import { usePrevious } from '@dnd-kit/utilities';
export function Steps({ componentMeta, darkMode, ...restProps }) {
const {
layoutPropertyChanged,
component,
dataQueries,
paramUpdated,
currentState,
eventsChanged,
apps,
allComponents,
pages,
} = restProps;
const getResolvedValue = useStore((state) => state.getResolvedValue, shallow);
const isDynamicOptionsEnabled = getResolvedValue(component?.component?.definition?.properties?.advanced?.value);
const variant = component?.component?.definition?.properties?.variant?.value;
const prevVariant = usePrevious(variant)
console.log("variant", component?.component?.definition);
const [options, setOptions] = useState([]);
const [hoveredOptionIndex, setHoveredOptionIndex] = useState(null);
let properties = [];
let additionalActions = [];
let optionsProperties = [];
for (const [key] of Object.entries(componentMeta?.properties)) {
if (componentMeta?.properties[key]?.section === 'additionalActions') {
additionalActions.push(key);
} else if (componentMeta?.properties[key]?.accordian === 'Options') {
optionsProperties.push(key);
} else {
properties.push(key);
}
}
// the default style of "number" & "titles" type are different for completed label
// TODO: Need to revisit this logic when text custom themes are implemented
useEffect(() => {
const completedLabelColor = component?.component?.definition?.styles?.completedLabel?.value;
if (variant !== prevVariant) {
if (variant === "numbers" && completedLabelColor === "#1B1F24") {
paramUpdated({ name: 'completedLabel' }, 'value', "#FFFFFF", 'styles', false, {});
} else if (variant === "titles" && completedLabelColor === "#FFFFFF") {
paramUpdated({ name: 'completedLabel' }, 'value', "#1B1F24", 'styles', false, {});
}
}
}, [variant])
const getItemStyle = (isDragging, draggableStyle) => ({
userSelect: 'none',
...draggableStyle,
});
const updateAllOptionsParams = (options, props) => {
paramUpdated({ name: 'steps' }, 'value', options, 'properties', false, props);
};
const generateNewOptions = () => {
let found = false;
let label = '';
let currentNumber = options.length + 1;
while (!found) {
label = `step ${currentNumber}`;
if (options.find((option) => option.name === label) === undefined) {
found = true;
}
currentNumber += 1;
}
return {
name: label,
id: currentNumber - 1,
tooltip: label,
visible: { value: '{{true}}' },
disabled: { value: '{{false}}' },
};
};
const handleAddOption = () => {
let _option = generateNewOptions();
const _items = [...options, _option];
setOptions(_items);
updateAllOptionsParams(_items);
};
const handleDeleteOption = (index) => {
const _items = options.filter((option, i) => i !== index);
setOptions(_items);
updateAllOptionsParams(_items, { isParamFromDropdownOptions: true });
};
const handleLabelChange = (propertyName, value, index) => {
const _options = options.map((option, i) => {
if (i === index) {
return {
...option,
[propertyName]: value,
};
}
return option;
});
setOptions(_options);
updateAllOptionsParams(_options);
};
const reorderOptions = async (startIndex, endIndex) => {
const result = [...options];
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
setOptions(result);
updateAllOptionsParams(result);
};
const onDragEnd = ({ source, destination }) => {
if (!destination || source?.index === destination?.index) {
return;
}
reorderOptions(source.index, destination.index);
};
const handleOnFxPress = (active, index, key) => {
const _options = options.map((option, i) => {
if (i === index) {
return {
...option,
[key]: {
...option[key],
fxActive: active,
},
};
}
return option;
});
setOptions(_options);
updateAllOptionsParams(_options);
};
const _renderOverlay = (item, index) => {
return (
<Popover className={`${darkMode && 'dark-theme theme-dark'}`} style={{ minWidth: '248px' }}>
<Popover.Body>
<div className="field mb-3" data-cy={`input-and-label-column-name`}>
<label data-cy={`label-column-name`} className="font-weight-500 mb-1 font-size-12">
{'Id'}
</label>
<CodeHinter
type={'basic'}
initialValue={item?.id + ''}
theme={darkMode ? 'monokai' : 'default'}
mode="javascript"
lineNumbers={false}
placeholder={'Option label'}
onChange={(value) => handleLabelChange('id', value, index)}
/>
</div>
<div className="field mb-3" data-cy={`input-and-label-column-name`}>
<label data-cy={`label-column-name`} className="font-weight-500 mb-1 font-size-12">
{'Label'}
</label>
<CodeHinter
type={'basic'}
initialValue={item?.name}
theme={darkMode ? 'monokai' : 'default'}
mode="javascript"
lineNumbers={false}
placeholder={'Option label'}
onChange={(value) => handleLabelChange('name', value, index)}
/>
</div>
<div className="field mb-3" data-cy={`input-and-label-column-name`}>
<label data-cy={`label-column-name`} className="font-weight-500 mb-1 font-size-12">
{'Tooltip'}
</label>
<CodeHinter
type={'basic'}
initialValue={item?.tooltip + ''}
theme={darkMode ? 'monokai' : 'default'}
mode="javascript"
lineNumbers={false}
placeholder={'Tooltip'}
onChange={(value) => handleLabelChange('tooltip', value, index)}
/>
</div>
<div className="field mb-2" data-cy={`input-and-label-column-name`}>
<CodeHinter
initialValue={item?.visible?.value}
theme={darkMode ? 'monokai' : 'default'}
mode="javascript"
lineNumbers={false}
component={component}
type={'fxEditor'}
paramLabel={'Visibility'}
onChange={(value) =>
handleLabelChange(
'visible',
{
value,
},
index
)
}
paramName={'visible'}
onFxPress={(active) => handleOnFxPress(active, index, 'visible')}
fxActive={item?.visible?.fxActive}
fieldMeta={{
type: 'toggle',
displayName: 'Make editable',
}}
paramType={'toggle'}
/>
</div>
<div className="field" data-cy={`input-and-label-column-name`}>
<CodeHinter
initialValue={item?.disabled?.value}
theme={darkMode ? 'monokai' : 'default'}
mode="javascript"
lineNumbers={false}
component={component}
type={'fxEditor'}
paramLabel={'Disable'}
paramName={'disable'}
onChange={(value) => handleLabelChange('disabled', { value }, index)}
onFxPress={(active) => handleOnFxPress(active, index, 'disabled')}
fxActive={item?.disabled?.fxActive}
fieldMeta={{
type: 'toggle',
displayName: 'Make editable',
}}
paramType={'toggle'}
/>
</div>
</Popover.Body>
</Popover>
);
};
const _renderOptions = () => {
return (
<List style={{ marginBottom: '20px' }}>
<DragDropContext
onDragEnd={(result) => {
onDragEnd(result);
}}
>
<Droppable droppableId="droppable">
{({ innerRef, droppableProps, placeholder }) => (
<div className="w-100" {...droppableProps} ref={innerRef}>
{options?.map((item, index) => {
return (
<Draggable key={item.name} draggableId={item.name} index={index}>
{(provided, snapshot) => (
<div
key={index}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
>
<OverlayTrigger
trigger="click"
placement="left"
rootClose
overlay={_renderOverlay(item, index)}
>
<div key={item.name + item.id}>
<ListGroup.Item
style={{ marginBottom: '8px', backgroundColor: 'var(--slate3)' }}
onMouseEnter={() => setHoveredOptionIndex(index)}
onMouseLeave={() => setHoveredOptionIndex(null)}
{...restProps}
>
<div className="row">
<div className="col-auto d-flex align-items-center">
<SortableList.DragHandle show />
</div>
<div className="col text-truncate cursor-pointer" style={{ padding: '0px' }}>
{getResolvedValue(item.name)}
</div>
<div className="col-auto">
{index === hoveredOptionIndex && (
<ButtonSolid
variant="danger"
size="xs"
className={'delete-icon-btn'}
onClick={(e) => {
e.stopPropagation();
handleDeleteOption(index);
}}
>
<span className="d-flex">
<Trash fill={'var(--tomato9)'} width={12} />
</span>
</ButtonSolid>
)}
</div>
</div>
</ListGroup.Item>
</div>
</OverlayTrigger>
</div>
)}
</Draggable>
);
})}
{placeholder}
</div>
)}
</Droppable>
</DragDropContext>
<AddNewButton onClick={handleAddOption} dataCy="add-new-dropdown-option" className="mt-0">
Add new option
</AddNewButton>
</List>
);
};
const isDynamicStepsEnabled = getResolvedValue(component?.component?.definition?.properties?.advanced?.value);
useEffect(() => {
setOptions(constructSteps());
}, [component?.id, isDynamicStepsEnabled]);
const constructSteps = () => {
try {
let optionsValue = isDynamicOptionsEnabled
? component?.component?.definition?.properties?.schema?.value
: component?.component?.definition?.properties?.steps?.value;
let options = [];
if (isDynamicOptionsEnabled || typeof optionsValue === 'string') {
options = getResolvedValue(optionsValue);
} else {
options = optionsValue?.map((option) => option);
}
return options.map((option) => {
const newOption = { ...option };
Object.keys(option).forEach((key) => {
if (typeof option[key]?.value === 'boolean') {
newOption[key]['value'] = `{{${option[key]?.value}}}`;
}
});
if (!('visible' in newOption)) {
newOption['visible'] = { value: '{{true}}' };
}
return newOption;
});
} catch (error) {
return [];
}
};
let items = [];
items.push({
title: 'Steps',
isOpen: true,
children: (
<>
{properties
.filter((property) => !optionsProperties.includes(property))
?.map((property) => {
if (property === 'steps') {
return (
<>
{renderElement(
component,
componentMeta,
paramUpdated,
dataQueries,
'advanced',
'properties',
currentState,
allComponents
)}
{isDynamicStepsEnabled
? renderElement(
component,
componentMeta,
paramUpdated,
dataQueries,
'schema',
'properties',
currentState,
allComponents
)
: _renderOptions()}
</>
);
}
// else if (property === 'variant') {
// return renderTest(
// component,
// componentMeta,
// paramUpdated,
// dataQueries,
// 'variant',
// 'properties',
// currentState,
// allComponents,
// handleLabelChange
// );
// }
return renderElement(
component,
componentMeta,
paramUpdated,
dataQueries,
property,
'properties',
currentState,
allComponents,
darkMode
);
})}
</>
),
});
items.push({
title: 'Events',
isOpen: true,
children: (
<EventManager
sourceId={component?.id}
eventSourceType="component"
eventMetaDefinition={componentMeta}
dataQueries={dataQueries}
components={allComponents}
eventsChanged={eventsChanged}
apps={apps}
darkMode={darkMode}
pages={pages}
/>
),
});
items.push({
title: `Additional Actions`,
isOpen: true,
children: additionalActions.map((property) => {
return renderElement(
component,
componentMeta,
paramUpdated,
dataQueries,
property,
'properties',
currentState,
allComponents,
darkMode,
componentMeta.properties?.[property]?.placeholder
);
}),
});
items.push({
title: 'Devices',
isOpen: true,
children: (
<>
{renderElement(
component,
componentMeta,
layoutPropertyChanged,
dataQueries,
'showOnDesktop',
'others',
currentState,
allComponents
)}
{renderElement(
component,
componentMeta,
layoutPropertyChanged,
dataQueries,
'showOnMobile',
'others',
currentState,
allComponents
)}
</>
),
});
return <Accordion items={items} />;
}
function renderTest(...props) {
const [
component,
componentMeta,
paramUpdated,
dataQueries,
param,
paramType,
currentState,
components = {},
darkMode = false,
placeholder = '',
validationFn,
] = props;
const value = componentMeta?.definition?.properties?.variant?.value;
return (
<div style={{ marginBottom: 8 }}>
<Switch
value={value}
onChange={(e) => {
paramUpdated({ name: 'variant' }, 'value', e, 'properties', false, props);
}}
meta={{
...componentMeta.properties[param],
fullWidth: true,
}}
paramName={param}
isIcon={false}
component={component.component.definition.name}
/>
</div>
);
}

View file

@ -36,6 +36,7 @@ import Inspect from '@/_ui/Icon/solidIcons/Inspect';
import classNames from 'classnames';
import { EMPTY_ARRAY } from '@/_stores/editorStore';
import { Select } from './Components/Select';
import { Steps } from './Components/Steps.jsx';
import { deepClone } from '@/_helpers/utilities/utils.helpers';
import useStore from '@/AppBuilder/_stores/store';
// import { componentTypes } from '@/Editor/WidgetManager/components';
@ -90,6 +91,7 @@ const NEW_REVAMPED_COMPONENTS = [
'VerticalDivider',
'ModalV2',
'Link',
'Steps',
];
export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selectedComponentId }) => {
@ -539,8 +541,8 @@ export const Inspector = ({ componentDefinitionChanged, darkMode, pages, selecte
componentMeta.displayName === 'Toggle Switch (Legacy)'
? 'Toggle (Legacy)'
: componentMeta.displayName === 'Toggle Switch'
? 'Toggle Switch'
: componentMeta.component,
? 'Toggle Switch'
: componentMeta.component,
})}
</small>
</span>
@ -740,6 +742,8 @@ const GetAccordion = React.memo(
case 'DatePickerV2':
case 'TimePicker':
return <DatetimePickerV2 {...restProps} componentName={componentName} />;
case 'Steps':
return <Steps {...restProps} />;
case 'PhoneInput':
return <PhoneInput {...restProps} />;
case 'CurrencyInput':

View file

@ -4,25 +4,38 @@ export const stepsConfig = {
description: 'Step-by-step navigation aid',
component: 'Steps',
properties: {
variant: {
type: 'switch',
displayName: 'Variant',
validation: { schema: { type: 'string' }, defaultValue: 'titles' },
options: [
{ displayName: 'Label', value: 'titles' },
{ displayName: 'Number', value: 'numbers' },
{ displayName: 'Plain', value: 'plain' },
],
accordian: 'label',
},
schema: {
type: 'code',
displayName: 'Schema',
conditionallyRender: {
key: 'advanced',
value: true,
},
accordian: 'Options',
},
steps: {
type: 'code',
displayName: 'Steps',
displayName: '',
showLabel: false,
validation: {
schema: {
type: 'array',
element: { type: 'object', object: { id: { type: 'number' } } },
element: { type: 'object' },
},
defaultValue: `[{ name: 'step 1'}, {name: 'step 2'}]`,
},
},
currentStep: {
type: 'code',
displayName: 'Current step',
validation: {
schema: { type: 'number' },
defaultValue: 1,
},
},
stepsSelectable: {
type: 'toggle',
displayName: 'Steps selectable',
@ -30,7 +43,38 @@ export const stepsConfig = {
schema: { type: 'boolean' },
defaultValue: false,
},
section: 'additionalActions',
},
disabledState: {
type: 'toggle',
displayName: 'Disable',
validation: { schema: { type: 'boolean' } },
section: 'additionalActions',
},
visibility: {
type: 'toggle',
displayName: 'Visibility',
validation: { schema: { type: 'boolean' }, defaultValue: true },
section: 'additionalActions',
},
advanced: {
type: 'toggle',
displayName: 'Dynamic options',
validation: {
schema: { type: 'boolean' },
defaultValue: true,
},
accordian: 'Options',
},
currentStep: {
type: 'code',
displayName: 'Current step',
validation: {
schema: { type: 'number' },
defaultValue: 1,
},
},
},
defaultSize: {
width: 22,
@ -40,46 +84,126 @@ export const stepsConfig = {
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
actions: [
{
handle: 'setStep',
displayName: 'Set step',
params: [
{
handle: 'option',
displayName: 'Option',
},
],
},
{
handle: 'setVisibility',
displayName: 'Set visibility',
params: [{ handle: 'visible', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
},
{
handle: 'setDisabled',
displayName: 'Set disabled',
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{true}}', type: 'toggle' }],
},
{
handle: 'resetSteps',
displayName: 'Reset steps',
params: [],
},
{
handle: 'setStepVisible',
displayName: 'Set step visible',
params: [
{
handle: 'id',
displayName: 'Step id',
},
{
handle: 'visibility',
displayName: 'visibility',
defaultValue: '{{false}}',
type: 'toggle',
},
],
},
{
handle: 'setStepDisable',
displayName: 'Set step disable',
params: [
{
handle: 'id',
displayName: 'Step id',
},
{
handle: 'disabled',
displayName: 'disabled',
defaultValue: '{{true}}',
type: 'toggle',
},
],
},
],
events: {
onSelect: { displayName: 'On select' },
},
styles: {
color: {
incompletedAccent: {
type: 'colorSwatches',
displayName: 'colorSwatches',
displayName: 'Incompleted accent',
validation: {
schema: { type: 'string' },
defaultValue: '#CCD1D5',
},
accordian: 'steps',
},
incompletedLabel: {
type: 'colorSwatches',
displayName: 'Incompleted label',
validation: {
schema: { type: 'string' },
defaultValue: '#1B1F24',
},
accordian: 'steps',
},
completedAccent: {
type: 'colorSwatches',
displayName: 'Completed accent',
validation: {
schema: { type: 'string' },
defaultValue: 'var(--primary-brand)',
},
accordian: 'steps',
},
textColor: {
completedLabel: {
type: 'colorSwatches',
displayName: 'Text color',
displayName: 'Completed label',
validation: {
schema: { type: 'string' },
defaultValue: '#000000',
defaultValue: '#1B1F24',
},
accordian: 'steps',
},
theme: {
type: 'select',
displayName: 'Theme',
currentStepLabel: {
type: 'colorSwatches',
displayName: 'Current step label',
validation: {
schema: { type: 'string' },
defaultValue: '#1B1F24',
},
accordian: 'steps',
},
padding: {
type: 'switch',
displayName: 'Padding',
validation: {
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
defaultValue: 'default',
},
options: [
{ name: 'titles', value: 'titles' },
{ name: 'numbers', value: 'numbers' },
{ name: 'plain', value: 'plain' },
{ displayName: 'Default', value: 'default' },
{ displayName: 'None', value: 'none' },
],
validation: {
schema: { type: 'string' },
defaultValue: 'titles',
},
},
visibility: {
type: 'toggle',
displayName: 'Visibility',
validation: {
schema: { type: 'boolean' },
defaultValue: true,
},
accordian: 'container',
},
},
exposedVariables: {
@ -92,17 +216,35 @@ export const stepsConfig = {
},
properties: {
steps: {
value: `{{ [{ name: 'step 1', tooltip: 'some tooltip', id: 1},{ name: 'step 2', tooltip: 'some tooltip', id: 2},{ name: 'step 3', tooltip: 'some tooltip', id: 3},{ name: 'step 4', tooltip: 'some tooltip', id: 4},{ name: 'step 5', tooltip: 'some tooltip', id: 5}]}}`,
value: [
{ name: 'step 1', tooltip: '', id: 1, visible: { value: true }, disabled: { value: false } },
{ name: 'step 2', tooltip: '', id: 2, visible: { value: true }, disabled: { value: false } },
{ name: 'step 3', tooltip: '', id: 3, visible: { value: true }, disabled: { value: false } },
{ name: 'step 4', tooltip: '', id: 4, visible: { value: true }, disabled: { value: false } },
{ name: 'step 5', tooltip: '', id: 5, visible: { value: true }, disabled: { value: false } },
],
},
schema: {
value: `{{ [{ name: 'step 1', tooltip: '', id: 1,visible: true, disabled: false},{ name: 'step 2', tooltip: '', id: 2,visible: true, disabled: false},{ name: 'step 3', tooltip: '', id: 3,visible: true, disabled: false},{ name: 'step 4', tooltip: '', id: 4,visible: true, disabled: false},{ name: 'step 5', tooltip: '', id: 5,visible: true, disabled: false}]}}`,
},
disabledState: { value: '{{false}}' },
variant: { value: 'titles' },
currentStep: { value: '{{3}}' },
stepsSelectable: { value: true },
advanced: { value: `{{false}}` },
visibility: { value: '{{true}}' },
},
events: [],
styles: {
visibility: { value: '{{true}}' },
theme: { value: 'titles' },
color: { value: 'var(--primary-brand)' },
textColor: { value: '' },
// color: { value: '' },
// textColor: { value: '' },
padding: { value: 'default' },
incompletedAccent: { value: '#E4E7EB' },
incompletedLabel: { value: '#1B1F24' },
completedAccent: { value: 'var(--primary-brand)' },
completedLabel: { value: '#1B1F24' },
currentStepLabel: { value: '#1B1F24' },
},
},
};

View file

@ -1,53 +1,226 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useRef } from 'react';
import { isExpectedDataType } from '@/_helpers/utils';
import { ToolTip } from '@/_components/ToolTip';
import './Steps.scss';
export const Steps = function Button({ properties, styles, fireEvent, setExposedVariable, height, darkMode, dataCy }) {
const { stepsSelectable } = properties;
const currentStep = isExpectedDataType(properties.currentStep, 'number');
const steps = isExpectedDataType(properties.steps, 'array');
const { color, theme, visibility, boxShadow } = styles;
export const Steps = function Steps({ properties, styles, fireEvent, setExposedVariable, height, darkMode, dataCy }) {
const { stepsSelectable, disabledState } = properties;
const visibility = isExpectedDataType(properties.visibility, 'boolean');
const currentStepId = isExpectedDataType(properties.currentStep, 'number');
const isDynamicStepsEnabled = isExpectedDataType(properties.advanced, 'boolean');
const steps = isDynamicStepsEnabled ? properties.schema : properties.steps;
const { color, boxShadow } = styles;
const textColor = darkMode && styles.textColor === '#000' ? '#fff' : styles.textColor;
const [activeStep, setActiveStep] = useState(null);
const { completedAccent, incompletedAccent, incompletedLabel, completedLabel, currentStepLabel } = styles;
const [stepsArr, setStepsArr] = useState(steps);
const [isVisible, setIsVisible] = useState(visibility);
const [isDisabled, setIsDisabled] = useState(disabledState);
const [activeStepId, setActiveStepId] = useState(currentStepId);
const theme = properties.variant;
const [progressBarWidth, setProgressBarWidth] = useState(0);
const [containerPadding, setContainerPadding] = useState(0);
const [containerWidth, setContainerWidth] = useState(0);
const [filteredSteps, setFilteredSteps] = useState([]);
const firstLabelRef = useRef(null);
const lastLabelRef = useRef(null);
const containerRef = useRef(null);
const currentStepIndex = filteredSteps.findIndex((step) => step.id == activeStepId);
useEffect(() => {
const sanitizedSteps = JSON.parse(JSON.stringify(steps || [])).map((step) => ({
...step,
visible: 'visible' in step ? step.visible : true,
disabled: 'disabled' in step ? step.disabled : false,
}));
const newFilteredSteps = (sanitizedSteps || []).filter((step) => step.visible);
setFilteredSteps(newFilteredSteps);
setStepsArr(sanitizedSteps);
}, [JSON.stringify(steps)]);
// Common function to calculate progress bar width and label padding
const calculateProgressBarWidth = () => {
if (!containerRef.current || theme !== 'titles') return;
const containerWidth = containerRef.current.offsetWidth;
setContainerWidth(containerWidth);
const stepWidth = 20; // width of dot + padding
const totalStepsWidth = filteredSteps.length * stepWidth;
const totalProgressBars = filteredSteps.length - 1;
if (filteredSteps.length === 1) {
setProgressBarWidth(containerWidth);
setContainerPadding(0); // No padding needed for single step
return;
}
// Calculate progress bar width
const progressBarWidth = (containerWidth - totalStepsWidth) / totalProgressBars;
setProgressBarWidth(Math.min(progressBarWidth, (containerWidth - totalStepsWidth) / filteredSteps.length));
// Calculate container padding
if (firstLabelRef.current && lastLabelRef.current) {
const labelWidth = (containerWidth - (filteredSteps.length - 1) - 4) / filteredSteps.length;
const firstLabelWidth = firstLabelRef.current.offsetWidth;
const lastLabelWidth = lastLabelRef.current.offsetWidth;
const maxLabelWidth = Math.max(firstLabelWidth, lastLabelWidth);
const calculatedPadding = (maxLabelWidth / 2) - 1;
setContainerPadding(Math.max(2, calculatedPadding)); // Ensure minimum padding of 2px
}
};
// Add resize observer to track container width and calculate progress bar width
useEffect(() => {
calculateProgressBarWidth();
if (theme !== 'titles') return;
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
calculateProgressBarWidth();
}
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => resizeObserver.disconnect();
}, [theme, JSON.stringify(steps), filteredSteps]);
// Dynamic styles for theming
const dynamicStyle = {
'--bgColor': styles.color,
'--textColor': textColor,
};
const activeStepHandler = (id) => {
const active = steps.filter((item) => item.id == id);
setExposedVariable('currentStepId', active[0].id);
fireEvent('onSelect');
setActiveStep(active[0].id);
'--completedAccent': completedAccent === '#4368E3' ? 'var(--primary-brand)' : completedAccent,
'--incompletedAccent': incompletedAccent === '#E4E7EB' ? 'var(--surfaces-surface-03)' : incompletedAccent,
'--incompletedLabel': incompletedLabel === '#1B1F24' ? 'var(--text-primary)' : incompletedLabel,
'--completedLabel': completedLabel === '#1B1F24' ? 'var(--text-primary)' : completedLabel,
'--currentStepLabel': currentStepLabel === '#1B1F24' ? 'var(--text-primary)' : currentStepLabel,
};
// Step click handler
const handleStepClick = (id) => {
const step = filteredSteps.find((item) => item.id == id);
if (step && !step.disabled && !isDisabled) {
setActiveStepId(step.id);
fireEvent('onSelect');
}
};
// Expose variables and methods
useEffect(() => {
setActiveStep(currentStep);
setExposedVariable('currentStepId', currentStep);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentStep]);
setExposedVariable('isVisible', isVisible);
setExposedVariable('isDisabled', isDisabled);
setExposedVariable('currentStepId', activeStepId);
setExposedVariable('steps', stepsArr);
setExposedVariable('setStepVisible', (stepId, visibility) => {
setStepsArr((prev) => {
const updatedSteps = prev.map((item) =>
item.id == stepId ? { ...item, visible: visibility } : item
);
setExposedVariable('steps', updatedSteps);
return updatedSteps;
});
});
setExposedVariable('setStepDisable', (stepId, disabled) => {
setStepsArr((prev) => {
const updatedSteps = prev.map((item) =>
item.id == stepId ? { ...item, disabled: disabled } : item
);
setExposedVariable('steps', updatedSteps);
return updatedSteps;
});
});
setExposedVariable('resetSteps', () => {
setActiveStepId(stepsArr.filter((step) => step.visible)?.[0]?.id);
});
setExposedVariable('setStep', (stepId) => {
if (!disabledState) setActiveStepId(stepId);
});
setExposedVariable('setVisibility', (visibility) => setIsVisible(visibility));
setExposedVariable('setDisable', (disabled) => setIsDisabled(disabled));
}, [isVisible, isDisabled, activeStepId, stepsArr, disabledState]);
// Update state from props
useEffect(() => setIsVisible(visibility), [visibility]);
useEffect(() => setIsDisabled(disabledState), [disabledState]);
useEffect(() => setActiveStepId(currentStepId), [currentStepId]);
if (!isVisible) return null;
return (
visibility && (
<div
className={`steps ${theme == 'numbers' && 'steps-counter '}`}
style={{ color: textColor, height, boxShadow }}
data-cy={dataCy}
>
{steps?.map((item) => (
<a
key={item.id}
className={`step-item ${item.id == activeStep && 'active'} ${!stepsSelectable && 'step-item-disabled'} ${
color && `step-${color}`
}`}
data-bs-toggle="tooltip"
title={item?.tooltip}
onClick={() => stepsSelectable && activeStepHandler(item.id)}
style={dynamicStyle}
>
{theme == 'titles' && item.name}
</a>
))}
<div
ref={containerRef}
className={`steps-container ${isDisabled ? 'disabled' : ''} ${filteredSteps.length === 1 ? 'single-step' : ''}`}
style={{
height,
boxShadow,
padding: theme === 'titles' ? `0 ${containerPadding}px` : 2,
paddingTop: theme === 'plain' ? `3px` : theme === 'numbers' ? `2px` : 0,
...dynamicStyle
}}
data-cy={dataCy}
>
<div className={`progress-line-container ${filteredSteps.length === 1 ? 'single-step' : ''}`}>
{filteredSteps.map((step, index) => {
const isStepDisabled = step.disabled;
const isCompleted = index < currentStepIndex;
const isActive = index === currentStepIndex;
const isUpcoming = index > currentStepIndex;
const isFirstStep = index === 0;
const isLastStep = index === filteredSteps.length - 1;
return (
<React.Fragment key={index}> {/* using index as key to avoid issues due to duplicate step ids */}
<ToolTip
show={!step.disabled && !isDisabled && step.tooltip}
message={step.tooltip || ''}
>
<div
onClick={() => stepsSelectable && handleStepClick(step.id)}
className={`milestone ${theme === 'numbers' ? 'numbers' : ''} ${isDisabled || isStepDisabled ? 'disabled' : ''
} ${isCompleted ? 'completed' : isActive ? 'active' : 'incomplete'}`}
>
{theme === 'numbers' ? (
index + 1
) : (
<>
<div
className={`dot ${isCompleted ? 'completed' : isActive ? 'active' : 'incomplete'}`}
style={{
border: `2px solid ${isCompleted ? completedAccent : isActive ? completedAccent : incompletedAccent}`,
backgroundColor: isActive ? 'transparent' : (isCompleted ? completedAccent : incompletedAccent)
}}
/>
{theme === 'titles' && (
<div
ref={isFirstStep ? firstLabelRef : isLastStep ? lastLabelRef : null}
className={`label ${isCompleted ? 'completed' : isActive ? 'active' : 'incomplete'}`}
style={{ maxWidth: `${progressBarWidth}px` }}
>
{step.name}
</div>
)}
</>
)}
</div>
</ToolTip>
{index < filteredSteps.length - 1 && (
<div
className={`step-connector ${isCompleted ? 'completed' : 'incomplete'}`}
/>
)}
</React.Fragment>
);
})}
</div>
)
</div>
);
};

View file

@ -0,0 +1,132 @@
.steps-container {
display: flex;
flex-direction: column;
width: 100%;
opacity: 1;
&.disabled {
opacity: 0.5;
}
&.single-step {
align-items: center;
}
.progress-line-container {
display: flex;
align-items: center;
gap: 2px;
&.single-step {
width: auto;
}
}
.milestone {
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: visible;
transition: all 0.3s ease;
cursor: pointer;
&.numbers {
width: 24px;
height: 24px;
border-radius: 50%;
font-size: 14px;
font-weight: 500;
box-sizing: content-box;
&.completed {
background-color: var(--completedAccent);
color: var(--completedLabel);
border: 2px solid var(--completedAccent);
}
&.active {
color: var(--currentStepLabel);
border: 2px solid var(--completedAccent);
}
&.incomplete {
background-color: var(--incompletedAccent);
color: var(--incompletedLabel);
border: 2px solid var(--incompletedAccent);
}
}
&.disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
.dot {
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
transition: all 0.3s ease;
box-sizing: content-box;
&.completed {
background-color: var(--completedAccent);
border: 2px solid var(--completedAccent);
}
&.active {
background-color: white;
border: 2px solid var(--primary-brand);
}
&.incomplete {
background-color: var(--incompletedAccent);
border: 2px solid var(--incompletedAccent);
}
}
.label {
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 18px;
text-align: center;
margin-top: 2px;
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: max-content;
&.completed {
color: var(--completedLabel);
}
&.active {
color: var(--completedLabel);
}
&.incomplete {
color: var(--incompletedLabel);
}
}
.step-connector {
flex-grow: 1;
height: 2px;
align-self: center;
transition: all 0.3s ease;
&.completed {
background-color: var(--completedAccent);
}
&.incomplete {
background-color: var(--incompletedAccent);
}
}
}

View file

@ -47,7 +47,7 @@ import { verticalDividerConfig } from './verticalDivider';
import { customComponentConfig } from './customComponent';
import { buttonGroupConfig } from './buttonGroup';
import { pdfConfig } from './pdf';
import { stepsConfig } from './steps';
// import { stepsConfig } from './steps';
import { kanbanConfig } from './kanban';
import { colorPickerConfig } from './colorPicker';
import { treeSelectConfig } from './treeSelect';
@ -106,7 +106,7 @@ export {
customComponentConfig,
buttonGroupConfig,
pdfConfig,
stepsConfig,
// stepsConfig,
kanbanConfig,
kanbanBoardConfig, //!Depreciated
colorPickerConfig,

View file

@ -1,108 +0,0 @@
export const stepsConfig = {
name: 'Steps',
displayName: 'Steps',
description: 'Step-by-step navigation aid',
component: 'Steps',
properties: {
steps: {
type: 'code',
displayName: 'Steps',
validation: {
schema: {
type: 'array',
element: { type: 'object', object: { id: { type: 'number' } } },
},
defaultValue: `[{ name: 'step 1'}, {name: 'step 2'}]`,
},
},
currentStep: {
type: 'code',
displayName: 'Current step',
validation: {
schema: { type: 'number' },
defaultValue: 1,
},
},
stepsSelectable: {
type: 'toggle',
displayName: 'Steps selectable',
validation: {
schema: { type: 'boolean' },
defaultValue: false,
},
},
},
defaultSize: {
width: 22,
height: 38,
},
others: {
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
events: {
onSelect: { displayName: 'On select' },
},
styles: {
color: {
type: 'color',
displayName: 'Color',
validation: {
schema: { type: 'string' },
defaultValue: '#000000',
},
},
textColor: {
type: 'color',
displayName: 'Text color',
validation: {
schema: { type: 'string' },
defaultValue: '#000000',
},
},
theme: {
type: 'select',
displayName: 'Theme',
options: [
{ name: 'titles', value: 'titles' },
{ name: 'numbers', value: 'numbers' },
{ name: 'plain', value: 'plain' },
],
validation: {
schema: { type: 'string' },
defaultValue: 'titles',
},
},
visibility: {
type: 'toggle',
displayName: 'Visibility',
validation: {
schema: { type: 'boolean' },
defaultValue: true,
},
},
},
exposedVariables: {
currentStepId: '3',
},
definition: {
others: {
showOnDesktop: { value: '{{true}}' },
showOnMobile: { value: '{{false}}' },
},
properties: {
steps: {
value: `{{ [{ name: 'step 1', tooltip: 'some tooltip', id: 1},{ name: 'step 2', tooltip: 'some tooltip', id: 2},{ name: 'step 3', tooltip: 'some tooltip', id: 3},{ name: 'step 4', tooltip: 'some tooltip', id: 4},{ name: 'step 5', tooltip: 'some tooltip', id: 5}]}}`,
},
currentStep: { value: '{{3}}' },
stepsSelectable: { value: true },
},
events: [],
styles: {
visibility: { value: '{{true}}' },
theme: { value: 'titles' },
color: { value: '' },
textColor: { value: '' },
},
},
};

View file

@ -7675,29 +7675,33 @@ fieldset:disabled .btn {
}
.rounded {
border-radius: 4px ;
border-radius: 4px;
}
.rounded-0 {
border-radius: 0 !important
}
.rounded-top-left{
.rounded-top-left {
border-top-left-radius: 4px;
}
.rounded-top-left-0{
.rounded-top-left-0 {
border-top-left-radius: 0 !important;
}
.rounded-top-right-0{
.rounded-top-right-0 {
border-top-right-radius: 0 !important;
}
.rounded-bottom-left-0{
.rounded-bottom-left-0 {
border-bottom-left-radius: 0 !important;
}
.rounded-bottom-right-0{
.rounded-bottom-right-0 {
border-bottom-right-radius: 0 !important;
}
.rounded-1 {
border-radius: 2px !important
}
@ -17484,8 +17488,8 @@ a.step-item:hover {
.step-item:not(:first-child):after {
position: absolute;
left: -50%;
width: 100%;
left: calc(-50% + 8px);
width: calc(100% - 16px);
content: "";
transform: translateY(-50%)
}
@ -17498,13 +17502,25 @@ a.step-item:hover {
box-sizing: content-box;
display: block;
content: "";
border: 2px solid #fff;
border: 2px solid transparent;
border-radius: 50%;
transform: translateX(-50%)
}
.step-item.active {
font-weight: 600
.steps.steps-counter {
.step-item:not(:first-child):after {
left: calc(-50% + 16px) !important;
width: calc(100% - 32px) !important;
}
}
.steps-counter .step-item:before {
color:var(--completedLabel) !important;
}
.steps .step-item.active:before{
color : var(--currentStepLabel) !important;
}
.step-item {
font-weight: 500;
}
.step-item.active:before {
@ -17521,7 +17537,7 @@ a.step-item:hover {
}
.step-item.active~.step-item:before {
color: #656d77 !important
color: var(--incompletedLabel) !important
}
.steps-counter {
@ -17549,7 +17565,8 @@ a.step-item:hover {
.steps-counter .step-item:before {
font-size: .75rem;
line-height: 1.5rem;
content: counter(steps)
content: counter(steps);
font-weight: 500 !important;
}
.steps-counter .step-item.active~.step-item:before {
@ -19156,4 +19173,4 @@ img {
background: #1f2936;
border-color: #dadcde
}
}
}

View file

@ -4760,15 +4760,18 @@ input[type="text"] {
.folder-list {
overflow-y: scroll;
scrollbar-width: thin;
scrollbar-color: #888 transparent;
scrollbar-color: #888 transparent;
&:hover {
&::-webkit-scrollbar {
display: block;
width: 5px;
}
&::-webkit-scrollbar-thumb {
background-color: #888;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
@ -6518,6 +6521,7 @@ div#driver-page-overlay {
// steps-widget
a.step-item-disabled {
text-decoration: none;
opacity: 0.5;
}
.steps {
@ -6527,34 +6531,45 @@ a.step-item-disabled {
.step-item.active~.step-item:after,
.step-item.active~.step-item:before {
background: #f3f5f5 !important;
background: var(--incompletedAccent) !important;
}
.step-item.active:before {
background: #ffffff !important;
background: transparent !important;
}
.steps .step-item.active:before {
border-color: #b4b2b2 !important;
border-color: var(--completedAccent) !important;
}
.steps-item {
color: var(--textColor) !important;
}
.step-item {
&.completed-label {
color: var(--completedLabel) !important;
}
&.incompleted-label {
color: var(--incompletedLabel) !important;
}
&.active-label {
color: var(--currentStepLabel) !important;
}
}
.step-item:before {
background: var(--bgColor) !important;
background-color: var(--completedAccent) !important;
// remaining code
}
.step-item:after {
background: var(--bgColor) !important;
background: var(--completedAccent) !important;
}
.step-item.active~.step-item {
color: var(--textColor) !important;
;
}
.notification-center-badge {
@ -9872,25 +9887,30 @@ tbody {
.workspace-settings-table-wrap {
max-width: 880px;
margin: 0 auto;
.tj-user-table-wrapper{
.tj-user-table-wrapper {
padding-right: 4px;
}
&:hover{
.tj-user-table-wrapper{
padding-right: 0px;
}
::-webkit-scrollbar{
display: block;
width: 4px;
}
::-webkit-scrollbar-track{
background: var(--base);
}
::-webkit-scrollbar-thumb{
background: var(--slate7);
border-radius: 6px;
}
}
}
&:hover {
.tj-user-table-wrapper {
padding-right: 0px;
}
::-webkit-scrollbar {
display: block;
width: 4px;
}
::-webkit-scrollbar-track {
background: var(--base);
}
::-webkit-scrollbar-thumb {
background: var(--slate7);
border-radius: 6px;
}
}
}
@ -12056,8 +12076,10 @@ tbody {
letter-spacing: -0.02em;
}
}
.sidebar-list-wrap.sidebar-list-wrap-with-banner.isAdmin {
height: calc(100vh - 371px);
&.resource-limit-reached {
height: calc(100vh - 371px);
}
@ -15801,6 +15823,7 @@ textarea.tj-text-input-widget{
.rest-api-options-codehinter {
height: 100%;
.cm-content>.cm-line {
// max-width: 357px !important;
}
@ -16232,19 +16255,20 @@ fieldset:disabled {
}
.datepicker-validation-half {
flex:1 1 calc(50% - 8px);
flex: 1 1 calc(50% - 8px);
}
.date-validation-wrapper {
.field {
height:24px;
height: 24px;
}
.code-flex-wrapper {
flex-wrap:wrap;
flex-wrap: wrap;
}
margin-bottom: 3px;
}
@ -16253,57 +16277,60 @@ fieldset:disabled {
}
.react-datepicker__day--disabled {
.react-datepicker__day--disabled {
color: #ccc !important;
}
.react-datepicker__time-list {
li.react-datepicker__time-list-item--disabled.react-datepicker__time-list-item {
color: #ccc !important;
}
.react-datepicker__time-list{
li.react-datepicker__time-list-item--disabled.react-datepicker__time-list-item {
color: #ccc !important;
}
}
.inspector-validation-date-picker {
.react-datepicker-wrapper{
input {
background-color: #fff;
}
input.dark-theme {
background-color: var(--slate3);
color: var(--slate12);
}
}
.inspector-validation-date-picker {
.react-datepicker-wrapper {
input {
background-color: #fff;
}
input.dark-theme {
background-color: var(--slate3);
color: var(--slate12);
}
}
}
.datetimepicker-component, #component-portal, .custom-inspector-validation-time-picker {
.datetimepicker-component,
#component-portal,
.custom-inspector-validation-time-picker {
.datepicker-component {
.react-datepicker {
border-radius: 10px;
box-shadow: 8px 8px 16px 0px #3032331A;
height:auto;
height: auto;
}
}
.react-datepicker-time-component {
border-radius: 10px;
width:auto;
width: auto;
.custom-time-input{
border-left:none;
border-radius:10px;
.custom-time-input {
border-left: none;
border-radius: 10px;
box-shadow: 8px 8px 16px 0px #3032331A;
}
.time-input-body {
padding-bottom:0px;
padding-bottom: 0px;
}
.time-col {
height: 200px;
}
@ -16312,28 +16339,32 @@ fieldset:disabled {
border-radius: 10px;
box-shadow: 8px 8px 16px 0px #3032331A;
}
.react-datepicker-time__input-container{
border-radius:10px;
.react-datepicker-time__input-container {
border-radius: 10px;
}
}
.dark-theme {
.react-datepicker__year-text, .react-datepicker__month-text {
.react-datepicker__year-text,
.react-datepicker__month-text {
color: #fff;
}
.react-datepicker__year-text:hover, .react-datepicker__month-text:hover {
background-color: #9ba1a6 ;
.react-datepicker__year-text:hover,
.react-datepicker__month-text:hover {
background-color: #9ba1a6;
}
}
.tj-datepicker-widget-year-selector:hover, .tj-datepicker-widget-month-selector:hover {
padding:1px 6px;
.tj-datepicker-widget-year-selector:hover,
.tj-datepicker-widget-month-selector:hover {
padding: 1px 6px;
}
.react-datepicker{
.react-datepicker {
display: grid;
grid-auto-flow: column;
border-top-right-radius: 0rem;
@ -16346,48 +16377,49 @@ fieldset:disabled {
justify-content: center;
align-items: center;
}
.react-datepicker__year-wrapper {
display:grid;
grid-template-columns:repeat(3, 1fr);
display: grid;
grid-template-columns: repeat(3, 1fr);
max-width: unset;
gap:10px;
gap: 10px;
}
.react-datepicker {
border-radius: 10px;
}
.react-datepicker__header--custom{
.react-datepicker__header--custom {
height: 34px;
margin-bottom: 14px;
}
.react-datepicker__year--container{
height:208px;
.react-datepicker__year--container {
height: 208px;
width: 250px;
box-shadow: 8px 8px 16px 0px #3032331A;
border-radius: 10px;
}
.react-datepicker__year-text--selected {
background-color: #4368E3 !important;
height:24px;
width:61.33px;
border-radius: 8px;
color: #fff ;
background-color: #4368E3 !important;
height: 24px;
width: 61.33px;
border-radius: 8px;
color: #fff;
}
.react-datepicker__year-text{
font-family:'IBM Plex Sans' ;
.react-datepicker__year-text {
font-family: 'IBM Plex Sans';
font-size: 12px;
line-height: 16px;
text-align: center;
font-weight: 400;
height:24px;
width:61.33px;
height: 24px;
width: 61.33px;
justify-content: center;
align-items: center;
display:flex;
display: flex;
}
}
@ -16402,42 +16434,42 @@ fieldset:disabled {
}
.react-datepicker__month-container {
height:208px;
height: 208px;
width: 250px;
box-shadow: 8px 8px 16px 0px #3032331A;
border-radius: 10px;
}
.react-datepicker__monthPicker {
display:flex;
display: flex;
flex-direction: column;
gap:10px;
gap: 10px;
}
.react-datepicker__month-text--selected {
background-color: #4368E3 !important;
height:24px;
width:61.33px;
height: 24px;
width: 61.33px;
border-radius: 8px;
color: #fff ;
color: #fff;
}
.react-datepicker__month-wrapper {
display:flex;
gap:24px;
display: flex;
gap: 24px;
}
.react-datepicker__month-text {
font-family:'IBM Plex Sans' ;
font-family: 'IBM Plex Sans';
font-size: 12px;
line-height: 16px;
text-align: center;
font-weight: 400;
height:24px;
width:61.33px;
height: 24px;
width: 61.33px;
justify-content: center;
align-items: center;
display:flex;
display: flex;
}
}
@ -16447,7 +16479,7 @@ fieldset:disabled {
.react-datepicker__month-container {
width: 100%;
width:250px;
width: 250px;
}
.react-datepicker__input-time-container {
@ -16462,12 +16494,12 @@ fieldset:disabled {
color: #ccc !important;
pointer-events: none;
}
.react-datepicker-time__input {
margin-left: 0px !important;
.dark-time-input {
color:#f4f6fa !important;
color: #f4f6fa !important;
background-color: var(--surfaces-surface-01) !important;
}
}
@ -16475,15 +16507,15 @@ fieldset:disabled {
.react-datepicker-wrapper {
width: 100%;
}
.react-datepicker-time__caption {
display:none;
display: none;
}
.custom-time-input {
background-color: #fff;
border-left: 1px solid #CCD1D5;
border-top-right-radius: 10px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
@ -16497,18 +16529,18 @@ fieldset:disabled {
border-bottom: 1px solid #CCD1D5;
font-weight: 500;
font-family: 'IBM Plex Sans';
color:#ACB2B9;
color: #ACB2B9;
}
.time-input-body {
padding-bottom: 12px;
}
.time-col {
margin-top: 5px;
overflow-y: auto;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
scrollbar-width: none;
height: 265px;
width: 62px;
}
@ -16516,12 +16548,12 @@ fieldset:disabled {
.selected-time {
background-color: #4368E3 !important;
border-radius: 6px;
color:#fff;
color: #fff;
}
.time-item {
width: 50px;
height:22px;
width: 50px;
height: 22px;
display: flex;
justify-content: center;
align-items: center;
@ -16861,16 +16893,17 @@ section.ai-message-prompt-input-wrapper {
.tj-inspector-timepicker.dark-theme {
.react-datepicker {
color:#f4f6fa !important;
.react-datepicker {
color: #f4f6fa !important;
background-color: var(--surfaces-surface-01) !important;
}
.react-datepicker, .react-datepicker__header {
.react-datepicker,
.react-datepicker__header {
border: 1px solid var(--borders-default);
background-color: #1f2936;
.react-datepicker-time__header{
.react-datepicker-time__header {
color: #fff !important;
}
@ -16878,25 +16911,27 @@ section.ai-message-prompt-input-wrapper {
}
.tj-inspector-timepicker {
padding:0px !important;
padding: 0px !important;
.react-datepicker__time-list {
scrollbar-width: none;
scrollbar-width: none;
}
.react-datepicker__triangle {
display:none;
display: none;
}
}
.custom-inspector-validation-date-picker, .custom-inspector-validation-time-picker {
.custom-inspector-validation-date-picker,
.custom-inspector-validation-time-picker {
flex-basis: 100% !important;
font-family: monospace;
font-size: 12px;
height:32px;
height: 32px;
.react-datepicker-wrapper {
width: 100%;
input {
width: 100%;
border: 1px solid var(--slate7);
@ -16904,23 +16939,23 @@ section.ai-message-prompt-input-wrapper {
background-color: var(--base);
background-color: #fff;
color: rgb(0, 92, 197);
height:32px;
height: 32px;
}
input.dark-theme {
background-color: #272822;
color: rgb(174, 129, 255);
}
}
}
.custom-inspector-validation-time-picker {
.custom-time-input {
border-left:none;
border-radius:10px;
border-left: none;
border-radius: 10px;
}
.time-col {
@ -16928,19 +16963,21 @@ section.ai-message-prompt-input-wrapper {
}
.react-datepicker__input-time-container {
border-radius:10px;
border-radius: 10px;
}
}
.custom-inspector-validation-time-picker-popper {
border-radius:10px;
border-radius: 10px;
}
.input-date-display-format, .input-date-time-format {
.input-date-display-format,
.input-date-time-format {
height: 60px;
.hide-fx {
opacity: 0;
transition: opacity 0.3s ease;
@ -16959,8 +16996,9 @@ section.ai-message-prompt-input-wrapper {
color: white;
}
.react-datepicker__day:hover, .react-datepicker__day--selecting-range-end {
background-color: var(--interactive-overlays-fill-hover) !important ;
.react-datepicker__day:hover,
.react-datepicker__day--selecting-range-end {
background-color: var(--interactive-overlays-fill-hover) !important;
}
.react-datepicker__day--keyboard-selected {
@ -16983,15 +17021,17 @@ section.ai-message-prompt-input-wrapper {
.tj-daterange-widget {
border-radius:10px;
border-radius: 10px;
box-shadow: 0px 8px 16px 0px #3032331A !important;
font-family: 'IBM Plex Sans';
.react-datepicker__day--in-selecting-range, .react-datepicker__day--in-range {
border-radius:0px;
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range {
border-radius: 0px;
background-color: #4368E31A !important;
}
.react-datepicker__header{
.react-datepicker__header {
background-color: var(--surfaces-surface-01);
padding: 6px 0px;
border: none;
@ -17002,44 +17042,48 @@ section.ai-message-prompt-input-wrapper {
background-color: #ededee !important;
}
.react-datepicker__day--selecting-range-start, .react-datepicker__day--selected, .react-datepicker__day--range-end {
border-radius:8px !important;
.react-datepicker__day--selecting-range-start,
.react-datepicker__day--selected,
.react-datepicker__day--range-end {
border-radius: 8px !important;
background-color: #4368E3 !important;
color: #fff !important;
}
.react-datepicker__day--in-range:has(+ .react-datepicker__day--range-end), .react-datepicker__day--in-selecting-range:has(+ .react-datepicker__day--selecting-range-end) {
.react-datepicker__day--in-range:has(+ .react-datepicker__day--range-end),
.react-datepicker__day--in-selecting-range:has(+ .react-datepicker__day--selecting-range-end) {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
.react-datepicker__day--in-range:has(+ .react-datepicker__day--range-end) {
box-shadow: 10px 0 0 0px #4368E31A;
}
.react-datepicker__day--range-start + .react-datepicker__day--in-range, .react-datepicker__day--selecting-range-start + .react-datepicker__day--in-selecting-range{
.react-datepicker__day--range-start+.react-datepicker__day--in-range,
.react-datepicker__day--selecting-range-start+.react-datepicker__day--in-selecting-range {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.react-datepicker__day--range-start + .react-datepicker__day--in-range {
.react-datepicker__day--range-start+.react-datepicker__day--in-range {
box-shadow: -10px 0 0 0px #4368E31A;
}
.react-datepicker__week {
.react-datepicker__day--in-range:first-of-type,
.react-datepicker__day--in-selecting-range:first-of-type,
.react-datepicker__day--outside-month + .react-datepicker__day--in-range,
.react-datepicker__day--outside-month + .react-datepicker__day--in-selecting-range{
.react-datepicker__day--in-range:first-of-type,
.react-datepicker__day--in-selecting-range:first-of-type,
.react-datepicker__day--outside-month+.react-datepicker__day--in-range,
.react-datepicker__day--outside-month+.react-datepicker__day--in-selecting-range {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.react-datepicker__day--in-range:last-of-type,
.react-datepicker__day--in-selecting-range:last-of-type,
.react-datepicker__day--in-range:has(+ .react-datepicker__day--outside-month),
.react-datepicker__day--in-selecting-range:has(+ .react-datepicker__day--outside-month){
.react-datepicker__day--in-range:last-of-type,
.react-datepicker__day--in-selecting-range:last-of-type,
.react-datepicker__day--in-range:has(+ .react-datepicker__day--outside-month),
.react-datepicker__day--in-selecting-range:has(+ .react-datepicker__day--outside-month) {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
@ -17057,8 +17101,8 @@ section.ai-message-prompt-input-wrapper {
}
.tj-datepicker-widget-right {
position: absolute;
right: 10px;
position: absolute;
right: 10px;
}
.tj-datepicker-widget-left {
@ -17081,41 +17125,42 @@ section.ai-message-prompt-input-wrapper {
}
.react-datepicker {
border-radius:10px !important;
border:none;
border-radius: 10px !important;
border: none;
}
}
.tj-daterangepicker-widget-month-selector, .tj-daterangepicker-widget-year-selector {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
padding-right: 4px;
/* Add some padding on the right to create space for custom arrow */
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23424242" width="18px" height="18px"><path d="M7 10l5 5 5-5z" /></svg>');
/* Add a custom arrow (you can use your own SVG) */
background-repeat: no-repeat;
background-position: right center;
border: none;
/* Remove the default border */
padding: 8px;
/* Adjust padding as needed */
cursor: pointer;
/* Add pointer cursor for better usability */
background: none;
padding: 0px;
height: 24px;
text-align: center;
color: var(--text-primary);
font-weight: 500;
width:auto;
.tj-daterangepicker-widget-month-selector,
.tj-daterangepicker-widget-year-selector {
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
padding-right: 4px;
/* Add some padding on the right to create space for custom arrow */
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23424242" width="18px" height="18px"><path d="M7 10l5 5 5-5z" /></svg>');
/* Add a custom arrow (you can use your own SVG) */
background-repeat: no-repeat;
background-position: right center;
border: none;
/* Remove the default border */
padding: 8px;
/* Adjust padding as needed */
cursor: pointer;
/* Add pointer cursor for better usability */
background: none;
padding: 0px;
height: 24px;
text-align: center;
color: var(--text-primary);
font-weight: 500;
width: auto;
}
.datepicker-widget {
.react-datepicker-wrapper{
width:100% !important;
.react-datepicker-wrapper {
width: 100% !important;
}
}
@ -17129,26 +17174,29 @@ section.ai-message-prompt-input-wrapper {
}
.tj-daterange-widget.react-datepicker-month-component {
border-radius:10px;
border-radius: 10px;
box-shadow: 0px 8px 16px 0px #3032331A !important;
font-family: 'IBM Plex Sans';
.react-datepicker__month-container {
box-shadow: none !important;
}
.react-datepicker__month-text {
height:26px !important;
height: 26px !important;
margin: 0px;
width:100% !important;
width: 100% !important;
}
.react-datepicker__month-text--in-selecting-range, .react-datepicker__month-text--in-range {
border-radius:0px;
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range {
border-radius: 0px;
background-color: #4368E31A !important;
color:#000;
color: #000;
}
.react-datepicker__header{
.react-datepicker__header {
background-color: var(--surfaces-surface-01);
padding: 6px 0px;
border: none;
@ -17161,45 +17209,49 @@ section.ai-message-prompt-input-wrapper {
}
.react-datepicker__month-text--selecting-range-start, .react-datepicker__month-text--selected, .react-datepicker__month-text--range-end {
border-radius:8px !important;
.react-datepicker__month-text--selecting-range-start,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--range-end {
border-radius: 8px !important;
background-color: #4368E3 !important;
color: #fff !important;
}
.react-datepicker__month-text--in-range:has(+ .react-datepicker__month-text--range-end), .react-datepicker__month-text--in-selecting-range:has(+ .react-datepicker__month-text--selecting-range-end) {
.react-datepicker__month-text--in-range:has(+ .react-datepicker__month-text--range-end),
.react-datepicker__month-text--in-selecting-range:has(+ .react-datepicker__month-text--selecting-range-end) {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
.react-datepicker__month-text--in-range:has(+ .react-datepicker__month-text--range-end) {
box-shadow: 10px 0 0 0px #4368E31A;
}
.react-datepicker__month-text--range-start + .react-datepicker__month-text--in-range, .react-datepicker__month-text--selecting-range-start + .react-datepicker__month-text--in-selecting-range{
.react-datepicker__month-text--range-start+.react-datepicker__month-text--in-range,
.react-datepicker__month-text--selecting-range-start+.react-datepicker__month-text--in-selecting-range {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.react-datepicker__month-text--range-start + .react-datepicker__month-text--in-range {
.react-datepicker__month-text--range-start+.react-datepicker__month-text--in-range {
box-shadow: -10px 0 0 0px #4368E31A;
}
.react-datepicker__month-wrapper{
gap:0px !important;
.react-datepicker__month-text--in-range:first-of-type,
.react-datepicker__month-text--in-selecting-range:first-of-type,
.react-datepicker__month-text--outside-month-text + .react-datepicker__month-text--in-range,
.react-datepicker__month-text--outside-month-text + .react-datepicker__month-text--in-selecting-range{
.react-datepicker__month-wrapper {
gap: 0px !important;
.react-datepicker__month-text--in-range:first-of-type,
.react-datepicker__month-text--in-selecting-range:first-of-type,
.react-datepicker__month-text--outside-month-text+.react-datepicker__month-text--in-range,
.react-datepicker__month-text--outside-month-text+.react-datepicker__month-text--in-selecting-range {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.react-datepicker__month-text--in-range:last-of-type,
.react-datepicker__month-text--in-selecting-range:last-of-type,
.react-datepicker__month-text--in-range:has(+ .react-datepicker__month-text--outside-month-text),
.react-datepicker__month-text--in-selecting-range:has(+ .react-datepicker__month-text--outside-month-text){
.react-datepicker__month-text--in-range:last-of-type,
.react-datepicker__month-text--in-selecting-range:last-of-type,
.react-datepicker__month-text--in-range:has(+ .react-datepicker__month-text--outside-month-text),
.react-datepicker__month-text--in-selecting-range:has(+ .react-datepicker__month-text--outside-month-text) {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
@ -17219,44 +17271,47 @@ section.ai-message-prompt-input-wrapper {
}
.tj-daterange-widget.react-datepicker-year-component {
border-radius:10px;
border-radius: 10px;
box-shadow: 0px 8px 16px 0px #3032331A !important;
font-family: 'IBM Plex Sans';
.react-datepicker__year-container {
box-shadow: none !important;
}
.react-datepicker__year-wrapper{
gap:0px !important;
.react-datepicker__year-wrapper {
gap: 0px !important;
.react-datepicker__year-text--in-range:first-of-type,
.react-datepicker__year-text--in-selecting-range:first-of-type{
.react-datepicker__year-text--in-range:first-of-type,
.react-datepicker__year-text--in-selecting-range:first-of-type {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.react-datepicker__year-text--in-range:last-of-type,
.react-datepicker__year-text--in-selecting-range:last-of-type{
.react-datepicker__year-text--in-range:last-of-type,
.react-datepicker__year-text--in-selecting-range:last-of-type {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
}
.react-datepicker__year-text {
height:26px !important;
height: 26px !important;
margin-top: 5px !important;
margin-bottom:5px !important;
margin-bottom: 5px !important;
margin: 0px;
width:62px !important;
width: 62px !important;
}
.react-datepicker__year-text--in-selecting-range, .react-datepicker__year-text--in-range {
border-radius:0px;
.react-datepicker__year-text--in-selecting-range,
.react-datepicker__year-text--in-range {
border-radius: 0px;
background-color: #4368E31A !important;
color:#000;
color: #000;
}
.react-datepicker__header{
.react-datepicker__header {
background-color: var(--surfaces-surface-01);
padding: 6px 0px;
border: none;
@ -17269,31 +17324,35 @@ section.ai-message-prompt-input-wrapper {
}
.react-datepicker__year-text--selecting-range-start, .react-datepicker__year-text--selected, .react-datepicker__year-text--range-end {
border-radius:8px !important;
.react-datepicker__year-text--selecting-range-start,
.react-datepicker__year-text--selected,
.react-datepicker__year-text--range-end {
border-radius: 8px !important;
background-color: #4368E3 !important;
color: #fff !important;
}
.react-datepicker__year-text--in-range:has(+ .react-datepicker__year-text--range-end), .react-datepicker__year-text--in-selecting-range:has(+ .react-datepicker__year-text--selecting-range-end) {
.react-datepicker__year-text--in-range:has(+ .react-datepicker__year-text--range-end),
.react-datepicker__year-text--in-selecting-range:has(+ .react-datepicker__year-text--selecting-range-end) {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
.react-datepicker__year-text--in-range:has(+ .react-datepicker__year-text--range-end) {
box-shadow: 10px 0 0 0px #4368E31A;
}
.react-datepicker__year-text--range-start + .react-datepicker__year-text--in-range, .react-datepicker__year-text--selecting-range-start + .react-datepicker__year-text--in-selecting-range{
.react-datepicker__year-text--range-start+.react-datepicker__year-text--in-range,
.react-datepicker__year-text--selecting-range-start+.react-datepicker__year-text--in-selecting-range {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.react-datepicker__year-text--range-start + .react-datepicker__year-text--in-range {
.react-datepicker__year-text--range-start+.react-datepicker__year-text--in-range {
box-shadow: -10px 0 0 0px #4368E31A;
}
}
.dark-theme {
@ -18783,6 +18842,7 @@ section.ai-message-prompt-input-wrapper {
font-style: normal;
font-weight: 400;
line-height: 18px;
&.dark {
background: #FFFAEB !important;
}

View file

@ -0,0 +1,81 @@
import { Component } from '@entities/component.entity';
import { EntityManager, MigrationInterface, QueryRunner } from 'typeorm';
import { processDataInBatches } from '@helpers/migration.helper';
export class StepsV2Migration1742369436314 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const componentTypes = ['Steps'];
const batchSize = 100;
const entityManager = queryRunner.manager;
for (const componentType of componentTypes) {
await processDataInBatches(
entityManager,
async (entityManager: EntityManager) => {
return await entityManager.find(Component, {
where: { type: componentType },
order: { createdAt: 'ASC' },
});
},
async (entityManager: EntityManager, components: Component[]) => {
await this.processUpdates(entityManager, components);
},
batchSize
);
}
}
public async down(queryRunner: QueryRunner): Promise<void> {}
private async processUpdates(entityManager, components) {
for (const component of components) {
const properties = component.properties;
const styles = component.styles;
const general = component.general;
const generalStyles = component.generalStyles;
const validation = component.validation;
if (styles.visibility) {
properties.visibility = styles.visibility;
delete styles.visibility;
}
if (styles.theme) {
properties['variant'] = styles.theme;
delete styles.theme;
}
if (styles.color) {
styles['completedAccent'] = styles.color;
}
delete styles.color;
if (styles.textColor) {
styles['completedLabel'] = styles.textColor;
styles['incompletedLabel'] = styles.textColor;
styles['currentStepLabel'] = styles.textColor;
}
delete styles.textColor;
if (properties.steps) {
properties['schema'] = properties.steps;
delete properties.steps;
properties['advanced'] = { value: '{{true}}' };
}
// if (properties.stepsSelectable) {
// properties.disabledState = styles.disabledState;
// delete styles.disabledState;
// }
// if (generalStyles?.boxShadow) {
// styles.boxShadow = generalStyles?.boxShadow;
// delete generalStyles?.boxShadow;
// }
await entityManager.update(Component, component.id, {
properties,
styles,
general,
generalStyles,
validation,
});
}
}
}

View file

@ -95,7 +95,9 @@ export class ComponentsService implements IComponentsService {
if (componentData.type === 'Table' && _.isArray(objValue)) {
return srcValue;
} else if (
(componentData.type === 'DropdownV2' || componentData.type === 'MultiselectV2') &&
(componentData.type === 'DropdownV2' ||
componentData.type === 'MultiselectV2' ||
componentData.type === 'Steps') &&
_.isArray(objValue)
) {
return _.isArray(srcValue) ? srcValue : Object.values(srcValue);

View file

@ -4,25 +4,38 @@ export const stepsConfig = {
description: 'Step-by-step navigation aid',
component: 'Steps',
properties: {
variant: {
type: 'switch',
displayName: 'Variant',
validation: { schema: { type: 'string' }, defaultValue: 'titles' },
options: [
{ displayName: 'Label', value: 'titles' },
{ displayName: 'Number', value: 'numbers' },
{ displayName: 'Plain', value: 'plain' },
],
accordian: 'label',
},
schema: {
type: 'code',
displayName: 'Schema',
conditionallyRender: {
key: 'advanced',
value: true,
},
accordian: 'Options',
},
steps: {
type: 'code',
displayName: 'Steps',
displayName: '',
showLabel: false,
validation: {
schema: {
type: 'array',
element: { type: 'object', object: { id: { type: 'number' } } },
element: { type: 'object' },
},
defaultValue: `[{ name: 'step 1'}, {name: 'step 2'}]`,
},
},
currentStep: {
type: 'code',
displayName: 'Current step',
validation: {
schema: { type: 'number' },
defaultValue: 1,
},
},
stepsSelectable: {
type: 'toggle',
displayName: 'Steps selectable',
@ -30,6 +43,36 @@ export const stepsConfig = {
schema: { type: 'boolean' },
defaultValue: false,
},
section: 'additionalActions',
},
disabledState: {
type: 'toggle',
displayName: 'Disable',
validation: { schema: { type: 'boolean' } },
section: 'additionalActions',
},
visibility: {
type: 'toggle',
displayName: 'Visibility',
validation: { schema: { type: 'boolean' }, defaultValue: true },
section: 'additionalActions',
},
advanced: {
type: 'toggle',
displayName: 'Dynamic options',
validation: {
schema: { type: 'boolean' },
defaultValue: true,
},
accordian: 'Options',
},
currentStep: {
type: 'code',
displayName: 'Current step',
validation: {
schema: { type: 'number' },
defaultValue: 1,
},
},
},
defaultSize: {
@ -40,46 +83,126 @@ export const stepsConfig = {
showOnDesktop: { type: 'toggle', displayName: 'Show on desktop' },
showOnMobile: { type: 'toggle', displayName: 'Show on mobile' },
},
actions: [
{
handle: 'setStep',
displayName: 'Set step',
params: [
{
handle: 'option',
displayName: 'Option',
},
],
},
{
handle: 'setVisibility',
displayName: 'Set visibility',
params: [{ handle: 'visible', displayName: 'Value', defaultValue: '{{false}}', type: 'toggle' }],
},
{
handle: 'setDisabled',
displayName: 'Set disabled',
params: [{ handle: 'disable', displayName: 'Value', defaultValue: '{{true}}', type: 'toggle' }],
},
{
handle: 'resetSteps',
displayName: 'Reset steps',
params: [],
},
{
handle: 'setStepVisible',
displayName: 'Set step visible',
params: [
{
handle: 'id',
displayName: 'Step id',
},
{
handle: 'visibility',
displayName: 'visibility',
defaultValue: '{{false}}',
type: 'toggle',
},
],
},
{
handle: 'setStepDisable',
displayName: 'Set step disable',
params: [
{
handle: 'id',
displayName: 'Step id',
},
{
handle: 'disabled',
displayName: 'disabled',
defaultValue: '{{true}}',
type: 'toggle',
},
],
},
],
events: {
onSelect: { displayName: 'On select' },
},
styles: {
color: {
incompletedAccent: {
type: 'colorSwatches',
displayName: 'Color',
displayName: 'Incompleted accent',
validation: {
schema: { type: 'string' },
defaultValue: '#CCD1D5',
},
accordian: 'steps',
},
incompletedLabel: {
type: 'colorSwatches',
displayName: 'Incompleted label',
validation: {
schema: { type: 'string' },
defaultValue: '#1B1F24',
},
accordian: 'steps',
},
completedAccent: {
type: 'colorSwatches',
displayName: 'Completed accent',
validation: {
schema: { type: 'string' },
defaultValue: 'var(--primary-brand)',
},
accordian: 'steps',
},
textColor: {
completedLabel: {
type: 'colorSwatches',
displayName: 'Text color',
displayName: 'Completed label',
validation: {
schema: { type: 'string' },
defaultValue: '#000000',
defaultValue: '#1B1F24',
},
accordian: 'steps',
},
theme: {
type: 'select',
displayName: 'Theme',
currentStepLabel: {
type: 'colorSwatches',
displayName: 'Current step label',
validation: {
schema: { type: 'string' },
defaultValue: '#1B1F24',
},
accordian: 'steps',
},
padding: {
type: 'switch',
displayName: 'Padding',
validation: {
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
defaultValue: 'default',
},
options: [
{ name: 'titles', value: 'titles' },
{ name: 'numbers', value: 'numbers' },
{ name: 'plain', value: 'plain' },
{ displayName: 'Default', value: 'default' },
{ displayName: 'None', value: 'none' },
],
validation: {
schema: { type: 'string' },
defaultValue: 'titles',
},
},
visibility: {
type: 'toggle',
displayName: 'Visibility',
validation: {
schema: { type: 'boolean' },
defaultValue: true,
},
accordian: 'container',
},
},
exposedVariables: {
@ -92,17 +215,35 @@ export const stepsConfig = {
},
properties: {
steps: {
value: `{{ [{ name: 'step 1', tooltip: 'some tooltip', id: 1},{ name: 'step 2', tooltip: 'some tooltip', id: 2},{ name: 'step 3', tooltip: 'some tooltip', id: 3},{ name: 'step 4', tooltip: 'some tooltip', id: 4},{ name: 'step 5', tooltip: 'some tooltip', id: 5}]}}`,
value: [
{ name: 'step 1', tooltip: '', id: 1, visible: { value: true }, disabled: { value: false } },
{ name: 'step 2', tooltip: '', id: 2, visible: { value: true }, disabled: { value: false } },
{ name: 'step 3', tooltip: '', id: 3, visible: { value: true }, disabled: { value: false } },
{ name: 'step 4', tooltip: '', id: 4, visible: { value: true }, disabled: { value: false } },
{ name: 'step 5', tooltip: '', id: 5, visible: { value: true }, disabled: { value: false } },
],
},
schema: {
value: `{{ [{ name: 'step 1', tooltip: '', id: 1,visible: true, disabled: false},{ name: 'step 2', tooltip: '', id: 2,visible: true, disabled: false},{ name: 'step 3', tooltip: '', id: 3,visible: true, disabled: false},{ name: 'step 4', tooltip: '', id: 4,visible: true, disabled: false},{ name: 'step 5', tooltip: '', id: 5,visible: true, disabled: false}]}}`,
},
disabledState: { value: '{{false}}' },
variant: { value: 'titles' },
currentStep: { value: '{{3}}' },
stepsSelectable: { value: true },
advanced: { value: `{{false}}` },
visibility: { value: '{{true}}' },
},
events: [],
styles: {
visibility: { value: '{{true}}' },
theme: { value: 'titles' },
color: { value: 'var(--primary-brand)' },
textColor: { value: '' },
// color: { value: '' },
// textColor: { value: '' },
padding: { value: 'default' },
incompletedAccent: { value: '#E4E7EB' },
incompletedLabel: { value: '#1B1F24' },
completedAccent: { value: '#4368E3' },
completedLabel: { value: '#1B1F24' },
currentStepLabel: { value: '#1B1F24' },
},
},
};

View file

@ -490,7 +490,7 @@ export class AppsUtilService implements IAppsUtilService {
if (['Table'].includes(currentComponentData?.component?.component) && isArray(objValue)) {
return srcValue;
} else if (
['DropdownV2', 'MultiselectV2'].includes(currentComponentData?.component?.component) &&
['DropdownV2', 'MultiselectV2', 'Steps'].includes(currentComponentData?.component?.component) &&
isArray(objValue)
) {
return isArray(srcValue) ? srcValue : Object.values(srcValue);