diff --git a/frontend/ee b/frontend/ee index 280578f99c..1b77a55670 160000 --- a/frontend/ee +++ b/frontend/ee @@ -1 +1 @@ -Subproject commit 280578f99c45224428f78ee16285b62f4c3631fd +Subproject commit 1b77a556709211daed8924821383db9dccc95eb5 diff --git a/frontend/package.json b/frontend/package.json index 45d94532f5..3821a370f5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -58,6 +58,7 @@ "dotenv": "^16.0.3", "draft-js": "^0.11.7", "draft-js-export-html": "^1.4.1", + "draft-js-import-html": "^1.4.1", "driver.js": "^0.9.8", "emoji-mart": "^5.5.2", "file-loader": "^6.2.0", diff --git a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js index 913d3a22df..5f362ba0b3 100644 --- a/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js +++ b/frontend/src/AppBuilder/AppCanvas/appCanvasUtils.js @@ -232,6 +232,7 @@ export const getAllChildComponents = (allComponents, parentId) => { const childTabId = componentParentId.split('-').at(-1); if (componentParentId === `${parentId}-${childTabId}`) { childComponent.isParentTabORCalendar = true; + childComponent.events = useStore.getState().eventsSlice.getEventsByComponentsId(componentId); childComponents.push(childComponent); // Recursively find children of the current child component const childrenOfChild = getAllChildComponents(allComponents, componentId); @@ -242,6 +243,7 @@ export const getAllChildComponents = (allComponents, parentId) => { if (componentParentId === parentId) { let childComponent = deepClone(allComponents[componentId]); childComponent.id = componentId; + childComponent.events = useStore.getState().eventsSlice.getEventsByComponentsId(componentId); childComponents.push(childComponent); // Recursively find children of the current child component diff --git a/frontend/src/AppBuilder/CodeEditor/CodehinterOverlayTriggers.jsx b/frontend/src/AppBuilder/CodeEditor/CodehinterOverlayTriggers.jsx new file mode 100644 index 0000000000..c79c473169 --- /dev/null +++ b/frontend/src/AppBuilder/CodeEditor/CodehinterOverlayTriggers.jsx @@ -0,0 +1,27 @@ +/* eslint-disable import/no-unresolved */ +import React from 'react'; +import { openSearchPanel } from '@codemirror/search'; +import './SearchBox.scss'; +import { Button as ButtonComponent } from '@/components/ui/Button/Button.jsx'; + +export const CodeHinterBtns = ({ view, isPanelOpen, renderCopilot }) => { + return ( +
+ {!isPanelOpen && ( + openSearchPanel(view)} + /> + )} + {renderCopilot && renderCopilot()} +
+ ); +}; diff --git a/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx index cbebcb0425..98af1dc9e4 100644 --- a/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx @@ -20,10 +20,12 @@ import { PreviewBox } from './PreviewBox'; import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; +import { syntaxTree } from '@codemirror/language'; import { search, searchKeymap, searchPanelOpen } from '@codemirror/search'; -import { handleSearchPanel, SearchBtn } from './SearchBox'; +import { handleSearchPanel } from './SearchBox'; import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks'; import { isInsideParent } from './utils'; +import { CodeHinterBtns } from './CodehinterOverlayTriggers'; const langSupport = Object.freeze({ javascript: javascript(), @@ -66,7 +68,7 @@ const MultiLineCodeEditor = (props) => { const context = useContext(CodeHinterContext); - const { suggestionList } = createReferencesLookup(context, true); + const { suggestionList: paramList } = createReferencesLookup(context, true); const currentValueRef = useRef(initialValue); @@ -74,6 +76,7 @@ const MultiLineCodeEditor = (props) => { const [editorView, setEditorView] = React.useState(null); + const [isSearchPanelOpen, setIsSearchPanelOpen] = React.useState(false); const { queryPanelKeybindings } = useQueryPanelKeyHooks(onChange, currentValueRef, 'multiline'); const handleOnBlur = () => { @@ -146,8 +149,29 @@ const MultiLineCodeEditor = (props) => { return suggestion.hint.includes(nearestSubstring); }); + const localVariables = new Set(); + + // Traverse the syntax tree to extract variable declarations + syntaxTree(context.state).iterate({ + enter: (node) => { + // JavaScript: Detect variable declarations (var, let, const) + if (node.name === 'VariableDefinition') { + const varName = context.state.sliceDoc(node.from, node.to); + if (varName && varName.startsWith(nearestSubstring)) localVariables.add(varName); + } + }, + }); + + // Convert Set to an array of completion suggestions + const localVariableSuggestions = [...localVariables].map((varName) => ({ + hint: varName, + type: 'variable', + })); + + const suggestionList = paramList.filter((paramSuggestion) => paramSuggestion.hint.includes(nearestSubstring)); + const suggestions = generateHints( - [...JSLangHints, ...autoSuggestionList, ...suggestionList], + [...localVariableSuggestions, ...JSLangHints, ...autoSuggestionList, ...suggestionList], null, nearestSubstring ).map((hint) => { @@ -204,6 +228,7 @@ const MultiLineCodeEditor = (props) => { return { from: context.pos, options: [...suggestions], + filter: false, }; } @@ -237,7 +262,7 @@ const MultiLineCodeEditor = (props) => { ]); // eslint-disable-next-line react-hooks/exhaustive-deps - const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), []); + const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [paramList]); const { handleTogglePopupExapand, isOpen, setIsOpen, forceUpdate } = portalProps; let cyLabel = paramLabel ? paramLabel.toLowerCase().trim().replace(/\s+/g, '-') : props.cyLabel; @@ -258,7 +283,7 @@ const MultiLineCodeEditor = (props) => { ref={wrapperRef} >
- + { isMultiEditor={true} isQueryManager={isInsideQueryPane} /> - {renderCopilot && renderCopilot()} { readOnly={readOnly} editable={editable} //for transformations in query manager onCreateEditor={(view) => setEditorView(view)} - onUpdate={(view) => { - const icon = document.querySelector('.codehinter-search-btn'); - if (searchPanelOpen(view.state)) { - icon.style.display = 'none'; - } else icon.style.display = 'block'; - }} + onUpdate={(view) => setIsSearchPanelOpen(searchPanelOpen(view.state))} />
{showPreview && ( diff --git a/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx b/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx index 28f7451b95..140ff2a7db 100644 --- a/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/SearchBox.jsx @@ -9,7 +9,6 @@ import { findPrevious, replaceNext, replaceAll, - openSearchPanel, } from '@codemirror/search'; import './SearchBox.scss'; import InputComponent from '@/components/ui/Input/Index.jsx'; @@ -162,22 +161,3 @@ function SearchPanel({ view }) { ); } - -export const SearchBtn = ({ view }) => { - return ( -
- openSearchPanel(view)} - /> -
- ); -}; diff --git a/frontend/src/AppBuilder/CodeEditor/SearchBox.scss b/frontend/src/AppBuilder/CodeEditor/SearchBox.scss index 24c948b0ee..79de28f28a 100644 --- a/frontend/src/AppBuilder/CodeEditor/SearchBox.scss +++ b/frontend/src/AppBuilder/CodeEditor/SearchBox.scss @@ -44,7 +44,5 @@ } .code-hinter-wrapper .codehinter-search-btn { - display: block; - padding-top: 1px; - z-index: 10000; + z-index: 1000; } \ No newline at end of file diff --git a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx index 65e6f2eadd..16514ca409 100644 --- a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx @@ -1,12 +1,18 @@ /* eslint-disable import/no-unresolved */ -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState, useContext } from 'react'; import { PreviewBox } from './PreviewBox'; import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip'; import { useTranslation } from 'react-i18next'; import { camelCase, isEmpty, noop, get } from 'lodash'; import CodeMirror from '@uiw/react-codemirror'; import { javascript } from '@codemirror/lang-javascript'; -import { autocompletion, completionKeymap, completionStatus, acceptCompletion } from '@codemirror/autocomplete'; +import { + autocompletion, + completionKeymap, + completionStatus, + acceptCompletion, + startCompletion, +} from '@codemirror/autocomplete'; import { defaultKeymap } from '@codemirror/commands'; import { keymap } from '@codemirror/view'; import FxButton from '../CodeBuilder/Elements/FxButton'; @@ -22,6 +28,8 @@ import CodeHinter from './CodeHinter'; import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils'; import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; +import { CodeHinterContext } from '../CodeBuilder/CodeHinterContext'; +import { createReferencesLookup } from '@/_stores/utils'; import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks'; const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...restProps }) => { @@ -73,6 +81,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r if (typeof initialValue === 'string' && (initialValue?.includes('components') || initialValue?.includes('queries'))) { newInitialValue = replaceIdsWithName(initialValue); } + //! Re render the component when the componentName changes as the initialValue is not updated // const { variablesExposedForPreview } = useContext(EditorContext) || {}; @@ -199,9 +208,14 @@ const EditorInput = ({ wrapperRef, showSuggestions, }) => { - const getServerSideGlobalSuggestions = useStore((state) => state.getServerSideGlobalSuggestions, shallow); + const codeHinterContext = useContext(CodeHinterContext); + const { suggestionList: paramHints } = createReferencesLookup(codeHinterContext, true); const getSuggestions = useStore((state) => state.getSuggestions, shallow); + const [codeMirrorView, setCodeMirrorView] = useState(undefined); + + const getServerSideGlobalSuggestions = useStore((state) => state.getServerSideGlobalSuggestions, shallow); + const { queryPanelKeybindings } = useQueryPanelKeyHooks(onBlurUpdate, currentValue, 'singleline'); const isInsideQueryManager = useMemo( @@ -209,16 +223,16 @@ const EditorInput = ({ [wrapperRef.current] ); function autoCompleteExtensionConfig(context) { - const hints = getSuggestions(); + const hintsWithoutParamHints = getSuggestions(); const serverHints = getServerSideGlobalSuggestions(isInsideQueryManager); - const allHints = { - ...hints, - appHints: [...hints.appHints, ...serverHints], - }; - let word = context.matchBefore(/\w*/); + const hints = { + ...hintsWithoutParamHints, + appHints: [...hintsWithoutParamHints.appHints, ...serverHints, ...paramHints], + }; + const totalReferences = (context.state.doc.toString().match(/{{/g) || []).length; let queryInput = context.state.doc.toString(); @@ -247,17 +261,18 @@ const EditorInput = ({ queryInput = '{{' + currentWord + '}}'; } - let completions = getAutocompletion(queryInput, validationType, allHints, totalReferences, originalQueryInput); + let completions = getAutocompletion(queryInput, validationType, hints, totalReferences, originalQueryInput); return { from: word.from, options: completions, validFor: /^\{\{.*\}\}$/, + filter: false, }; } // eslint-disable-next-line react-hooks/exhaustive-deps - const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [isInsideQueryManager]); + const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [isInsideQueryManager, paramHints]); const autoCompleteConfig = autocompletion({ override: [overRideFunction], @@ -424,6 +439,9 @@ const EditorInput = ({ ref={previewRef} > { + setCodeMirrorView(view); + }} value={currentValue} placeholder={placeholder} height={isInsideQueryPane ? '100%' : showLineNumbers ? '400px' : '100%'} @@ -460,11 +478,16 @@ const EditorInput = ({ theme={theme} indentWithTab={false} readOnly={disabled} + onKeyDown={(event) => { + if (event.key === 'Backspace') { + startCompletion(codeMirrorView); + } + }} /> - - - + + + ); }; diff --git a/frontend/src/AppBuilder/CodeEditor/autocompleteExtensionConfig.js b/frontend/src/AppBuilder/CodeEditor/autocompleteExtensionConfig.js index e1d597c957..d845fa521e 100644 --- a/frontend/src/AppBuilder/CodeEditor/autocompleteExtensionConfig.js +++ b/frontend/src/AppBuilder/CodeEditor/autocompleteExtensionConfig.js @@ -67,7 +67,8 @@ export const getAutocompletion = (input, fieldType, hints, totalReferences = 1, originalQueryInput, searchInput ); - return orderSuggestions(suggestions, fieldType); + + return suggestions; }; function orderSuggestions(suggestions, validationType) { @@ -90,10 +91,18 @@ export const generateHints = (hints, totalReferences = 1, input, searchText) => const hasDepth = currentWord.includes('.'); const lastDepth = getLastSubstring(currentWord); - const displayLabel = getLastDepth(displayedHint); + let displayLabel = getLastDepth(displayedHint); + + if (type != 'js_method') { + const currentWordDepth = currentWord.split('.').length; + displayLabel = hint + .split('.') + .slice(currentWordDepth - 1) + .join('.'); + } return { - displayLabel: lastDepth === '' ? displayedHint : displayLabel, + displayLabel, label: displayedHint, info: displayedHint, type: type === 'js_method' ? 'js_methods' : type?.toLowerCase(), @@ -154,40 +163,24 @@ export const generateHints = (hints, totalReferences = 1, input, searchText) => }; function filterHintsByDepth(input, hints) { - if (input === '') return hints; + const inputParts = input.split('.'); + const inputDepth = inputParts.length + 1; - const inputDepth = input.includes('.') ? input.split('.').length : 0; - - const filteredHints = hints.filter((cm) => { - const hintParts = cm.hint.split('.'); - - let shouldInclude = - (cm.hint.startsWith(input) && hintParts.length === inputDepth + 1) || - (cm.hint.startsWith(input) && hintParts.length === inputDepth); - - const shouldFuzzyMatch = !shouldInclude ? hintParts.length > inputDepth : false; - - if (shouldFuzzyMatch) { - // fuzzy match - let matchedDepth = -1; - for (let i = 0; i < hintParts.length; i++) { - if (hintParts[i].includes(input)) { - matchedDepth = i; - break; - } - } - - if (matchedDepth !== -1) { - shouldInclude = hintParts.length === matchedDepth + 1; - } - } else if (input.endsWith('.')) { - shouldInclude = cm.hint.startsWith(input) && hintParts.length === inputDepth; - } - - return shouldInclude; + const hintsWithDepth = hints.map((hint) => { + const hintParts = hint.hint.split('.'); + return { + ...hint, + depth: hintParts.length, + }; }); - return filteredHints; + const filteredHints = hintsWithDepth.filter((hint) => { + return hint.depth <= inputDepth; + }); + + const sortedHints = filteredHints.sort((hint1, hint2) => hint1.depth - hint2.depth); + + return sortedHints; } export function findNearestSubstring(inputStr, currentCurosorPos) { diff --git a/frontend/src/AppBuilder/QueryManager/Components/ChangeDataSource.jsx b/frontend/src/AppBuilder/QueryManager/Components/ChangeDataSource.jsx index 244668cf8a..85958cd97b 100644 --- a/frontend/src/AppBuilder/QueryManager/Components/ChangeDataSource.jsx +++ b/frontend/src/AppBuilder/QueryManager/Components/ChangeDataSource.jsx @@ -1,8 +1,20 @@ -import React from 'react'; +import React, { useState } from 'react'; import Select from '@/_ui/Select'; import { decodeEntities } from '@/_helpers/utils'; +import usePopoverObserver from '@/AppBuilder/_hooks/usePopoverObserver'; export const ChangeDataSource = ({ dataSources, onChange, value, isVersionReleased }) => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + + usePopoverObserver( + document.getElementsByClassName('query-details')[0], + document.querySelector('.change-data-source-select.react-select__control'), + document.querySelector('.change-data-source-select.react-select__menu'), + isMenuOpen, + () => (document.querySelector('.change-data-source-select.react-select__menu').style.display = 'block'), + () => (document.querySelector('.change-data-source-select.react-select__menu').style.display = 'none') + ); + return ( + { + 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 {} + + 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, + }); + } + } +} diff --git a/server/ee b/server/ee index 69bdefb1f3..8155e72286 160000 --- a/server/ee +++ b/server/ee @@ -1 +1 @@ -Subproject commit 69bdefb1f3f1d35bd6e7231e50799ff10a77a60f +Subproject commit 8155e72286b253042ede33cab64a5099d441ff44 diff --git a/server/src/modules/apps/services/component.service.ts b/server/src/modules/apps/services/component.service.ts index a7538f5f40..fcc01e52f0 100644 --- a/server/src/modules/apps/services/component.service.ts +++ b/server/src/modules/apps/services/component.service.ts @@ -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); diff --git a/server/src/modules/apps/services/widget-config/container.js b/server/src/modules/apps/services/widget-config/container.js index 6dc9a679a4..04ddf805d9 100644 --- a/server/src/modules/apps/services/widget-config/container.js +++ b/server/src/modules/apps/services/widget-config/container.js @@ -3,8 +3,8 @@ export const containerConfig = { displayName: 'Container', description: 'Group components', defaultSize: { - width: 10, - height: 200, + width: 13, + height: 480, }, component: 'Container', others: { diff --git a/server/src/modules/apps/services/widget-config/steps.js b/server/src/modules/apps/services/widget-config/steps.js index c8b9753d9a..4400a19137 100644 --- a/server/src/modules/apps/services/widget-config/steps.js +++ b/server/src/modules/apps/services/widget-config/steps.js @@ -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' }, }, }, }; diff --git a/server/src/modules/apps/util.service.ts b/server/src/modules/apps/util.service.ts index f17fa876a7..3db7df4a99 100644 --- a/server/src/modules/apps/util.service.ts +++ b/server/src/modules/apps/util.service.ts @@ -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); diff --git a/server/src/modules/data-queries/service.ts b/server/src/modules/data-queries/service.ts index 48aa236cee..5337c6739a 100644 --- a/server/src/modules/data-queries/service.ts +++ b/server/src/modules/data-queries/service.ts @@ -22,7 +22,7 @@ export class DataQueriesService implements IDataQueriesService { protected readonly dataQueryRepository: DataQueryRepository, protected readonly dataQueryUtilService: DataQueriesUtilService, protected readonly dataSourceRepository: DataSourcesRepository - ) {} + ) { } async getAll(versionId: string) { const queries = await this.dataQueryRepository.getAll(versionId); @@ -30,9 +30,6 @@ export class DataQueriesService implements IDataQueriesService { // serialize for (const query of queries) { - if (query.dataSource.type === DataSourceTypes.STATIC) { - delete query['dataSourceId']; - } delete query['dataSource']; const decamelizeQuery = decamelizeKeys(query); diff --git a/server/src/modules/organization-themes/constants/index.ts b/server/src/modules/organization-themes/constants/index.ts index 5f8041bc52..581c2181c0 100644 --- a/server/src/modules/organization-themes/constants/index.ts +++ b/server/src/modules/organization-themes/constants/index.ts @@ -31,11 +31,11 @@ export const TJDefaultTheme: Definition = { light: '#1B1F24', dark: '#CFD3D8', }, - secondary: { + placeholder: { light: '#6A727C', dark: '#858C94', }, - tertiary: { + disabled: { light: '#ACB2B9', dark: '#545B64', }, @@ -48,15 +48,15 @@ export const TJDefaultTheme: Definition = { large: 0, }, colors: { - primary: { + default: { light: '#CCD1D5', dark: '#3C434B', }, - secondary: { + weak: { light: '#E4E7EB', dark: '#EEF0F1', }, - tertiary: { + disabled: { light: '#E4E7EB', dark: '#F6F8FA', }, @@ -64,15 +64,15 @@ export const TJDefaultTheme: Definition = { }, systemStatus: { colors: { - primary: { + success: { light: '#1E823B', dark: '#318344', }, - secondary: { + error: { light: '#D72D39', dark: '#D03F43', }, - tertiary: { + warning: { light: '#BF4F03', dark: '#BA5722', }, @@ -84,6 +84,18 @@ export const TJDefaultTheme: Definition = { light: '#F6F6F6', dark: '#121518', }, + surface1: { + light: '#FFFFFF', + dark: '#1E2226', + }, + surface2: { + light: '#F6F8FA', + dark: '#2B3036', + }, + surface3: { + light: '#E4E7EB', + dark: '#3C434B', + }, }, }, }; diff --git a/server/src/modules/organization-themes/dto/index.ts b/server/src/modules/organization-themes/dto/index.ts index c87f7b1565..eb7ac608cd 100644 --- a/server/src/modules/organization-themes/dto/index.ts +++ b/server/src/modules/organization-themes/dto/index.ts @@ -33,12 +33,12 @@ class TextColors { @IsOptional() @ValidateNested() @Type(() => Color) - secondary?: Color; + placeholder?: Color; @IsOptional() @ValidateNested() @Type(() => Color) - tertiary?: Color; + disabled?: Color; } class Text { @@ -64,17 +64,17 @@ class BorderRadius { class BorderColors { @ValidateNested() @Type(() => Color) - primary: Color; + default: Color; @IsOptional() @ValidateNested() @Type(() => Color) - secondary?: Color; + weak?: Color; @IsOptional() @ValidateNested() @Type(() => Color) - tertiary?: Color; + disabled?: Color; } class Border { @@ -90,17 +90,17 @@ class Border { class SystemStatusColors { @ValidateNested() @Type(() => Color) - primary: Color; + success: Color; @IsOptional() @ValidateNested() @Type(() => Color) - secondary?: Color; + error?: Color; @IsOptional() @ValidateNested() @Type(() => Color) - tertiary?: Color; + warning?: Color; } class SystemStatus { @@ -121,6 +121,18 @@ class SurfaceColors { @ValidateNested() @Type(() => AppBackgroundColor) appBackground: AppBackgroundColor; + + @ValidateNested() + @Type(() => Color) + surface1: Color; + + @ValidateNested() + @Type(() => Color) + surface2: Color; + + @ValidateNested() + @Type(() => Color) + surface3: Color; } class Surface {