mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
Merge branch 'feat/grid-appbuilder-improvement' into builder-performance-platform-part/release
This commit is contained in:
commit
34bf75dee0
34 changed files with 710 additions and 438 deletions
|
|
@ -7,6 +7,7 @@ import { shallow } from 'zustand/shallow';
|
|||
import { useAppVersionStore } from '@/_stores/appVersionStore';
|
||||
import { useEditorStore } from '@/_stores/editorStore';
|
||||
import { useEnvironmentsAndVersionsStore } from '@/_stores/environmentsAndVersionsStore';
|
||||
import { useAppDataStore } from '@/_stores/appDataStore';
|
||||
|
||||
const appVersionLoadingStatus = Object.freeze({
|
||||
loading: 'loading',
|
||||
|
|
@ -85,7 +86,17 @@ const RenderComponent = ({
|
|||
const darkMode = localStorage.getItem('darkMode') === 'true';
|
||||
|
||||
const selectVersion = (id) => {
|
||||
appVersionService
|
||||
const currentVersionId = useAppDataStore.getState().currentVersionId;
|
||||
|
||||
const isSameVersionSelected = currentVersionId === id;
|
||||
|
||||
if (isSameVersionSelected) {
|
||||
return toast('You are already editing this version', {
|
||||
icon: '⚠️',
|
||||
});
|
||||
}
|
||||
|
||||
return appVersionService
|
||||
.getAppVersionData(appId, id)
|
||||
.then((data) => {
|
||||
const isCurrentVersionReleased = data.currentVersionId ? true : false;
|
||||
|
|
|
|||
|
|
@ -88,8 +88,7 @@ const Portal = ({ children, ...restProps }) => {
|
|||
const PopupIcon = ({ callback, icon, tip, position, isMultiEditor = false }) => {
|
||||
const size = 16;
|
||||
const topRef = isNumber(position?.height) ? Math.floor(position?.height) - 30 : 32;
|
||||
let top = isMultiEditor ? 370 : topRef > 32 ? topRef : 0;
|
||||
|
||||
let top = isMultiEditor ? 270 : topRef > 32 ? topRef : 0;
|
||||
return (
|
||||
<div className="d-flex justify-content-end w-100 position-absolute codehinter-popup-icon" style={{ top: top }}>
|
||||
<OverlayTrigger
|
||||
|
|
|
|||
|
|
@ -12,14 +12,7 @@ import Card from 'react-bootstrap/Card';
|
|||
// eslint-disable-next-line import/no-unresolved
|
||||
import { JsonViewer } from '@textea/json-viewer';
|
||||
|
||||
export const PreviewBox = ({
|
||||
currentValue,
|
||||
validationSchema,
|
||||
setErrorStateActive,
|
||||
componentId,
|
||||
fxActive,
|
||||
setErrorMessage,
|
||||
}) => {
|
||||
export const PreviewBox = ({ currentValue, validationSchema, setErrorStateActive, componentId, setErrorMessage }) => {
|
||||
const { variablesExposedForPreview } = useContext(EditorContext);
|
||||
|
||||
const customVariables = variablesExposedForPreview?.[componentId] ?? {};
|
||||
|
|
@ -27,10 +20,8 @@ export const PreviewBox = ({
|
|||
const [resolvedValue, setResolvedValue] = useState('');
|
||||
const [error, setError] = useState(null);
|
||||
const [coersionData, setCoersionData] = useState(null);
|
||||
|
||||
const getPreviewContent = (content, type) => {
|
||||
if (!content) return currentValue;
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case 'Object':
|
||||
|
|
@ -75,12 +66,7 @@ export const PreviewBox = ({
|
|||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
const [valid, _error, newValue, resolvedValue] = resolveReferences(
|
||||
currentValue,
|
||||
validationSchema,
|
||||
customVariables,
|
||||
fxActive
|
||||
);
|
||||
const [valid, _error, newValue, resolvedValue] = resolveReferences(currentValue, validationSchema, customVariables);
|
||||
|
||||
if (!validationSchema || isEmpty(validationSchema)) {
|
||||
return setResolvedValue(newValue);
|
||||
|
|
@ -345,7 +331,6 @@ const PreviewCodeBlock = ({ code, isExpectValue = false }) => {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="p-2 pt-0">
|
||||
<pre
|
||||
|
|
@ -366,7 +351,9 @@ const PreviewCodeBlock = ({ code, isExpectValue = false }) => {
|
|||
padding: '0',
|
||||
}}
|
||||
>
|
||||
{prettyPrintedJson}
|
||||
{prettyPrintedJson?.startsWith('{{')
|
||||
? prettyPrintedJson?.replace(/{{/g, '').replace(/}}/g, '')
|
||||
: prettyPrintedJson}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -34,15 +34,9 @@ const SingleLineCodeEditor = ({ suggestions, componentName, fieldMeta = {}, fxAc
|
|||
|
||||
useEffect(() => {
|
||||
if (typeof initialValue !== 'string') return;
|
||||
|
||||
if (fxActive && initialValue?.startsWith('{{')) {
|
||||
const _value = initialValue?.replace(/{{/g, '').replace(/}}/g, '');
|
||||
return setCurrentValue(_value);
|
||||
}
|
||||
|
||||
setCurrentValue(initialValue);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [componentName, initialValue, fxActive]);
|
||||
}, [componentName, initialValue]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
|
|
@ -80,7 +74,7 @@ const SingleLineCodeEditor = ({ suggestions, componentName, fieldMeta = {}, fxAc
|
|||
setErrorStateActive={setErrorStateActive}
|
||||
ignoreValidation={restProps?.ignoreValidation || isEmpty(validation)}
|
||||
componentId={restProps?.componentId ?? null}
|
||||
fxActive={fxActive}
|
||||
// fxActive={fxActive}
|
||||
isWorkspaceVariable={isWorkspaceVariable}
|
||||
errorStateActive={errorStateActive}
|
||||
previewPlacement={restProps?.cyLabel === 'canvas-bg-colour' ? 'top' : 'left-start'}
|
||||
|
|
@ -99,7 +93,6 @@ const SingleLineCodeEditor = ({ suggestions, componentName, fieldMeta = {}, fxAc
|
|||
cyLabel={restProps.cyLabel}
|
||||
portalProps={portalProps}
|
||||
componentName={componentName}
|
||||
fxActive={fxActive}
|
||||
{...restProps}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -124,7 +117,6 @@ const EditorInput = ({
|
|||
renderPreview,
|
||||
portalProps,
|
||||
ignoreValidation,
|
||||
fxActive,
|
||||
lang,
|
||||
isFocused,
|
||||
componentId,
|
||||
|
|
@ -138,15 +130,15 @@ const EditorInput = ({
|
|||
|
||||
if (totalReferences > 1) {
|
||||
const currentWord = queryInput.split('{{').pop().split('}}')[0];
|
||||
queryInput = fxActive ? currentWord : `{{${currentWord}}}`;
|
||||
queryInput = currentWord;
|
||||
}
|
||||
|
||||
let completions = getAutocompletion(queryInput, validationType, hints, fxActive, totalReferences);
|
||||
let completions = getAutocompletion(queryInput, validationType, hints, totalReferences);
|
||||
|
||||
return {
|
||||
from: word.from,
|
||||
options: completions,
|
||||
validFor: !fxActive ? /^\{\{.*\}\}$/ : '',
|
||||
validFor: /^\{\{.*\}\}$/,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -168,18 +160,17 @@ const EditorInput = ({
|
|||
setCurrentValue(val);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const handleOnBlur = React.useCallback(() => {
|
||||
setFirstTimeFocus(false);
|
||||
if (ignoreValidation) {
|
||||
return onBlurUpdate(currentValue);
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
const _value = fxActive ? `{{${currentValue}}}` : currentValue;
|
||||
|
||||
onBlurUpdate(_value);
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (!error || currentValue == '') {
|
||||
const _value = currentValue;
|
||||
onBlurUpdate(_value);
|
||||
}
|
||||
}, 0);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentValue, error]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
export const getAutocompletion = (input, fieldType, hints, fxActive = false, totalReferences = 1) => {
|
||||
if (!fxActive && (!input.startsWith('{{') || !input.endsWith('}}'))) return [];
|
||||
|
||||
const actualInput = !fxActive ? input.replace(/{{|}}/g, '') : input;
|
||||
export const getAutocompletion = (input, fieldType, hints, totalReferences = 1) => {
|
||||
if (!input.startsWith('{{') || !input.endsWith('}}')) return [];
|
||||
|
||||
const actualInput = input.replace(/{{|}}/g, '');
|
||||
let JSLangHints = [];
|
||||
|
||||
if (fieldType) {
|
||||
|
|
@ -50,7 +49,7 @@ export const getAutocompletion = (input, fieldType, hints, fxActive = false, tot
|
|||
if (autoSuggestionList.length === 0 && !cm.hint.includes(actualInput)) return true;
|
||||
});
|
||||
|
||||
const suggestions = generateHints([...jsHints, ...autoSuggestionList], fxActive, totalReferences);
|
||||
const suggestions = generateHints([...jsHints, ...autoSuggestionList], totalReferences);
|
||||
return orderSuggestions(suggestions, fieldType).map((cm, index) => ({ ...cm, boost: 100 - index }));
|
||||
};
|
||||
|
||||
|
|
@ -64,7 +63,7 @@ function orderSuggestions(suggestions, validationType) {
|
|||
return [...matchingSuggestions, ...otherSuggestions];
|
||||
}
|
||||
|
||||
export const generateHints = (hints, isFxHinter = false, totalReferences = 1) => {
|
||||
export const generateHints = (hints, totalReferences = 1) => {
|
||||
if (!hints) return [];
|
||||
|
||||
const suggestions = hints.map(({ hint, type }) => {
|
||||
|
|
@ -91,9 +90,7 @@ export const generateHints = (hints, isFxHinter = false, totalReferences = 1) =>
|
|||
insert: completion.label,
|
||||
};
|
||||
|
||||
let anchorSelection = isFxHinter
|
||||
? pickedCompletionConfig.insert.length
|
||||
: pickedCompletionConfig.insert.length + 2;
|
||||
let anchorSelection = pickedCompletionConfig.insert.length + 2;
|
||||
|
||||
if (completion.type === 'js_methods') {
|
||||
pickedCompletionConfig.from = from;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cm-widgetBuffer {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.cm-base-autocomplete {
|
||||
|
|
@ -153,18 +157,35 @@
|
|||
}
|
||||
}
|
||||
|
||||
.query-manager-sort-filter-popup {
|
||||
.cm-base-autocomplete {
|
||||
position: fixed !important;
|
||||
top: 130px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.canvas-codehinter-container {
|
||||
.cm-base-autocomplete {
|
||||
position: fixed !important;
|
||||
top: 500px !important;
|
||||
left: 38px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.widget-code-editor {
|
||||
height: 100%;
|
||||
|
||||
.cm-content {
|
||||
max-width: 220px !important;
|
||||
max-width: 100% !important;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.cm-placeholder {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.code-hinter-wrapper {
|
||||
.cm-editor {
|
||||
min-height: 32px;
|
||||
|
|
@ -224,6 +245,7 @@
|
|||
|
||||
.cm-tooltip-autocomplete {
|
||||
@extend .cm-base-autocomplete;
|
||||
top: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,6 +299,7 @@
|
|||
overflow-y: auto !important;
|
||||
overflow-x: hidden !important;
|
||||
padding: 2px !important;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.cm-focused {
|
||||
|
|
@ -315,8 +338,6 @@
|
|||
|
||||
.code-hinter-preview-card-body::-webkit-scrollbar {
|
||||
width: 4px !important;
|
||||
/* for vertical scrollbars */
|
||||
;
|
||||
}
|
||||
|
||||
.code-hinter-preview-card-body::-webkit-scrollbar-track {
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ const resolveWorkspaceVariables = (query, state) => {
|
|||
resolvedStr = resolvedStr.replace(serverMatch, 'HiddenEnvironmentVariable');
|
||||
error = 'Server variables cannot be resolved in the client.';
|
||||
} else {
|
||||
const [resolvedCode, err] = resolveCode(code, state);
|
||||
const [resolvedCode, err] = resolveCode(code);
|
||||
|
||||
if (!resolvedCode) {
|
||||
error = err ? err : `Cannot resolve ${query}`;
|
||||
|
|
@ -126,7 +126,7 @@ const resolveWorkspaceVariables = (query, state) => {
|
|||
return [valid, error, resolvedStr];
|
||||
};
|
||||
|
||||
function resolveCode(code, state, customObjects = {}, withError = true, reservedKeyword, isJsCode) {
|
||||
function resolveCode(code, customObjects = {}, withError = true, reservedKeyword, isJsCode) {
|
||||
let result = '';
|
||||
let error;
|
||||
|
||||
|
|
@ -135,6 +135,7 @@ function resolveCode(code, state, customObjects = {}, withError = true, reserved
|
|||
error = `Cannot resolve function call ${code}`;
|
||||
} else {
|
||||
try {
|
||||
const state = useCurrentStateStore.getState();
|
||||
const evalFunction = Function(
|
||||
[
|
||||
'variables',
|
||||
|
|
@ -199,8 +200,7 @@ const resolveMultiDynamicReferences = (code, lookupTable) => {
|
|||
|
||||
resolvedValue = resolvedValue.replace(variable, res);
|
||||
} else {
|
||||
const currentState = useCurrentStateStore.getState();
|
||||
const [resolvedCode] = resolveCode(variableToResolve, currentState, {}, true, [], true);
|
||||
const [resolvedCode] = resolveCode(variableToResolve, {}, true, [], true);
|
||||
|
||||
resolvedValue = resolvedCode;
|
||||
}
|
||||
|
|
@ -210,40 +210,40 @@ const resolveMultiDynamicReferences = (code, lookupTable) => {
|
|||
return resolvedValue;
|
||||
};
|
||||
|
||||
export const resolveReferences = (query, validationSchema, customResolvers = {}, fxActive = false) => {
|
||||
export const resolveReferences = (query, validationSchema, customResolvers = {}) => {
|
||||
if (!query || typeof query !== 'string') return [false, null, null];
|
||||
|
||||
let resolvedValue = query;
|
||||
let error = null;
|
||||
|
||||
const currentState = useCurrentStateStore.getState();
|
||||
|
||||
//Todo : remove resolveWorkspaceVariables when workspace variables are removed
|
||||
if (query?.startsWith('%%') && query?.endsWith('%%')) {
|
||||
return resolveWorkspaceVariables(query, currentState);
|
||||
return resolveWorkspaceVariables(query);
|
||||
}
|
||||
|
||||
if ((!validationSchema || isEmpty(validationSchema)) && (!query?.includes('{{') || !query?.includes('}}'))) {
|
||||
return [true, error, resolvedValue];
|
||||
}
|
||||
|
||||
if (validationSchema && !fxActive && !query?.includes('{{') && !query?.includes('}}')) {
|
||||
if (validationSchema && !query?.includes('{{') && !query?.includes('}}')) {
|
||||
const [valid, errors, newValue] = validateComponentProperty(query, validationSchema);
|
||||
return [valid, errors, newValue, resolvedValue];
|
||||
}
|
||||
|
||||
const hasMultiDynamicVariables = getDynamicVariables(query);
|
||||
const hasMultiDynamicVariables = getDynamicVariables(query)?.length > 1;
|
||||
|
||||
const { lookupTable } = useResolveStore.getState();
|
||||
if (isEmpty(validationSchema) && hasMultiDynamicVariables) {
|
||||
if (hasMultiDynamicVariables) {
|
||||
resolvedValue = resolveMultiDynamicReferences(query, lookupTable);
|
||||
} else {
|
||||
let value = !fxActive ? query?.replace(/{{|}}/g, '').trim() : query;
|
||||
let value = query?.replace(/{{|}}/g, '').trim();
|
||||
|
||||
if (fxActive && (value.startsWith('#') || value.includes('table-'))) {
|
||||
if (value.startsWith('#') || value.includes('table-')) {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
const { toResolveReference, jsExpression, jsExpMatch } = inferJSExpAndReferences(value, lookupTable.hints);
|
||||
const { toResolveReference, jsExpression, jsExpMatch } =
|
||||
lookupTable.hints || lookupTable.hints.has
|
||||
? inferJSExpAndReferences(value, lookupTable.hints)
|
||||
: { toResolveReference: null, jsExpression: null, jsExpMatch: null };
|
||||
|
||||
if (!jsExpMatch && toResolveReference && lookupTable.hints.has(toResolveReference)) {
|
||||
const idToLookUp = lookupTable.hints.get(toResolveReference);
|
||||
|
|
@ -253,10 +253,10 @@ export const resolveReferences = (query, validationSchema, customResolvers = {},
|
|||
let jscode = value.replace(toResolveReference, resolvedValue);
|
||||
jscode = value.replace(toResolveReference, `'${resolvedValue}'`);
|
||||
|
||||
resolvedValue = resolveCode(jscode, currentState, customResolvers);
|
||||
resolvedValue = resolveCode(jscode, customResolvers);
|
||||
}
|
||||
} else {
|
||||
const [resolvedCode, errorRef] = resolveCode(value, currentState, customResolvers, true, [], true);
|
||||
const [resolvedCode, errorRef] = resolveCode(value, customResolvers, true, [], true);
|
||||
|
||||
resolvedValue = resolvedCode;
|
||||
error = errorRef || null;
|
||||
|
|
@ -309,7 +309,7 @@ const inferJSExpAndReferences = (code, hintsMap) => {
|
|||
const potentialReference = referenceChain ? referenceChain + '.' + segment : segment;
|
||||
|
||||
// Check if the potential reference exists in hintsMap
|
||||
if (hintsMap.has(potentialReference)) {
|
||||
if (hintsMap.has && hintsMap.has(potentialReference)) {
|
||||
// If it does, update the referenceChain
|
||||
referenceChain = potentialReference;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
|||
import { toast } from 'react-hot-toast';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import * as XLSX from 'xlsx/xlsx.mjs';
|
||||
import { useCurrentState } from '@/_stores/currentStateStore';
|
||||
|
||||
import { useAppInfo } from '@/_stores/appDataStore';
|
||||
|
||||
export const FilePicker = ({
|
||||
|
|
@ -19,7 +19,6 @@ export const FilePicker = ({
|
|||
setExposedVariable,
|
||||
dataCy,
|
||||
}) => {
|
||||
const currentState = useCurrentState();
|
||||
//* properties definitions
|
||||
const instructionText =
|
||||
component.definition.properties.instructionText?.value ?? 'Drag and drop files here or click to select files';
|
||||
|
|
@ -30,31 +29,25 @@ export const FilePicker = ({
|
|||
const fileType = component.definition.properties.fileType?.value ?? 'image/*';
|
||||
const maxSize = component.definition.properties.maxSize?.value ?? 1048576;
|
||||
const minSize = component.definition.properties.minSize?.value ?? 0;
|
||||
const parseContent = resolveWidgetFieldValue(
|
||||
component.definition.properties.parseContent?.value ?? false,
|
||||
currentState
|
||||
);
|
||||
const parseContent = resolveWidgetFieldValue(component.definition.properties.parseContent?.value);
|
||||
const fileTypeFromExtension = component.definition.properties.parseFileType?.value ?? 'auto-detect';
|
||||
const parsedEnableDropzone =
|
||||
typeof enableDropzone !== 'boolean' ? resolveWidgetFieldValue(enableDropzone, currentState) : true;
|
||||
const parsedEnablePicker =
|
||||
typeof enablePicker !== 'boolean' ? resolveWidgetFieldValue(enablePicker, currentState) : true;
|
||||
const parsedEnableDropzone = typeof enableDropzone !== 'boolean' ? resolveWidgetFieldValue(enableDropzone) : true;
|
||||
const parsedEnablePicker = typeof enablePicker !== 'boolean' ? resolveWidgetFieldValue(enablePicker) : true;
|
||||
|
||||
const parsedMaxFileCount =
|
||||
typeof maxFileCount !== 'number' ? resolveWidgetFieldValue(maxFileCount, currentState) : maxFileCount;
|
||||
const parsedMaxFileCount = typeof maxFileCount !== 'number' ? resolveWidgetFieldValue(maxFileCount) : maxFileCount;
|
||||
const parsedEnableMultiple =
|
||||
typeof enableMultiple !== 'boolean' ? resolveWidgetFieldValue(enableMultiple, currentState) : enableMultiple;
|
||||
const parsedFileType = resolveWidgetFieldValue(fileType, currentState);
|
||||
const parsedMinSize = typeof fileType !== 'number' ? resolveWidgetFieldValue(minSize, currentState) : minSize;
|
||||
const parsedMaxSize = typeof fileType !== 'number' ? resolveWidgetFieldValue(maxSize, currentState) : maxSize;
|
||||
typeof enableMultiple !== 'boolean' ? resolveWidgetFieldValue(enableMultiple) : enableMultiple;
|
||||
const parsedFileType = resolveWidgetFieldValue(fileType);
|
||||
const parsedMinSize = typeof fileType !== 'number' ? resolveWidgetFieldValue(minSize) : minSize;
|
||||
const parsedMaxSize = typeof fileType !== 'number' ? resolveWidgetFieldValue(maxSize) : maxSize;
|
||||
//* styles definitions
|
||||
const widgetVisibility = component.definition.styles?.visibility?.value ?? true;
|
||||
const disabledState = component.definition.styles?.disabledState?.value ?? false;
|
||||
|
||||
const parsedDisabledState =
|
||||
typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState;
|
||||
typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState) : disabledState;
|
||||
const parsedWidgetVisibility =
|
||||
typeof widgetVisibility !== 'boolean' ? resolveWidgetFieldValue(widgetVisibility, currentState) : widgetVisibility;
|
||||
typeof widgetVisibility !== 'boolean' ? resolveWidgetFieldValue(widgetVisibility) : widgetVisibility;
|
||||
|
||||
const { events: allAppEvents } = useAppInfo();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import { GoogleMap, LoadScript, Marker, Autocomplete, Polygon } from '@react-google-maps/api';
|
||||
import { resolveReferences, resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
import { darkModeStyles } from './styles';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
|
@ -12,7 +12,6 @@ export const Map = function Map({
|
|||
component,
|
||||
darkMode,
|
||||
onComponentClick,
|
||||
currentState,
|
||||
onComponentOptionChanged,
|
||||
onComponentOptionsChanged,
|
||||
onEvent,
|
||||
|
|
@ -27,27 +26,27 @@ export const Map = function Map({
|
|||
const { t } = useTranslation();
|
||||
|
||||
const addNewMarkersProp = component.definition.properties.addNewMarkers;
|
||||
const canAddNewMarkers = addNewMarkersProp ? resolveReferences(addNewMarkersProp.value, currentState) : false;
|
||||
const canAddNewMarkers = addNewMarkersProp ? resolveWidgetFieldValue(addNewMarkersProp.value) : false;
|
||||
|
||||
const canSearchProp = component.definition.properties.canSearch;
|
||||
const canSearch = canSearchProp ? resolveReferences(canSearchProp.value, currentState) : false;
|
||||
const canSearch = canSearchProp ? resolveWidgetFieldValue(canSearchProp.value) : false;
|
||||
const widgetVisibility = component.definition.styles?.visibility?.value ?? true;
|
||||
const disabledState = component.definition.styles?.disabledState?.value ?? false;
|
||||
|
||||
const parsedDisabledState =
|
||||
typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState;
|
||||
typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState) : disabledState;
|
||||
|
||||
let parsedWidgetVisibility = widgetVisibility;
|
||||
|
||||
try {
|
||||
parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []);
|
||||
parsedWidgetVisibility = resolveWidgetFieldValue(parsedWidgetVisibility);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
const [gmap, setGmap] = useState(null);
|
||||
const [autoComplete, setAutoComplete] = useState(null);
|
||||
const [mapCenter, setMapCenter] = useState(resolveReferences(center, currentState));
|
||||
const [mapCenter, setMapCenter] = useState(() => resolveWidgetFieldValue(center));
|
||||
const [markers, setMarkers] = useState(defaultMarkers);
|
||||
|
||||
const containerStyle = {
|
||||
|
|
@ -97,7 +96,7 @@ export const Map = function Map({
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
const resolvedCenter = resolveReferences(center, currentState);
|
||||
const resolvedCenter = resolveWidgetFieldValue(center);
|
||||
setMapCenter(resolvedCenter);
|
||||
onComponentOptionsChanged(component, [['center', addMapUrlToJson(resolvedCenter)]]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
@ -128,7 +127,7 @@ export const Map = function Map({
|
|||
|
||||
useEffect(() => {
|
||||
setExposedVariable('setLocation', async function (lat, lng) {
|
||||
if (lat && lng) setMapCenter(resolveReferences({ lat, lng }, currentState));
|
||||
if (lat && lng) setMapCenter(resolveWidgetFieldValue({ lat, lng }));
|
||||
});
|
||||
}, [setMapCenter]);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import './numberinput.scss';
|
|||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
import * as Icons from '@tabler/icons-react';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import { resolveReferences } from '@/_helpers/utils';
|
||||
import { useCurrentState } from '@/_stores/currentStateStore';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
|
||||
const tinycolor = require('tinycolor2');
|
||||
import Label from '@/_ui/Label';
|
||||
|
||||
|
|
@ -38,9 +38,9 @@ export const NumberInput = function NumberInput({
|
|||
} = styles;
|
||||
|
||||
const textColor = darkMode && ['#232e3c', '#000000ff'].includes(styles.textColor) ? '#fff' : styles.textColor;
|
||||
const isMandatory = resolveReferences(component?.definition?.validation?.mandatory?.value, currentState) ?? false;
|
||||
const minValue = resolveReferences(component?.definition?.validation?.minValue?.value, currentState) ?? null;
|
||||
const maxValue = resolveReferences(component?.definition?.validation?.maxValue?.value, currentState) ?? null;
|
||||
const isMandatory = resolveWidgetFieldValue(component?.definition?.validation?.mandatory?.value) ?? false;
|
||||
const minValue = resolveWidgetFieldValue(component?.definition?.validation?.minValue?.value) ?? null;
|
||||
const maxValue = resolveWidgetFieldValue(component?.definition?.validation?.maxValue?.value) ?? null;
|
||||
|
||||
const [visibility, setVisibility] = useState(properties.visibility);
|
||||
const [loading, setLoading] = useState(loadingState);
|
||||
|
|
@ -50,7 +50,7 @@ export const NumberInput = function NumberInput({
|
|||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const inputRef = useRef(null);
|
||||
const currentState = useCurrentState();
|
||||
|
||||
const [disable, setDisable] = useState(disabledState || loadingState);
|
||||
const labelRef = useRef();
|
||||
const _width = (width / 100) * 70; // Max width which label can go is 70% for better UX calculate width based on this value
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { resolveReferences } from '@/_helpers/utils';
|
||||
import { useCurrentState } from '@/_stores/currentStateStore';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
|
||||
import * as Icons from '@tabler/icons-react';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
|
|
@ -44,8 +44,8 @@ export const PasswordInput = function PasswordInput({
|
|||
const [visibility, setVisibility] = useState(properties.visibility);
|
||||
const { isValid, validationError } = validate(passwordValue);
|
||||
const [showValidationError, setShowValidationError] = useState(false);
|
||||
const currentState = useCurrentState();
|
||||
const isMandatory = resolveReferences(component?.definition?.validation?.mandatory?.value, currentState);
|
||||
|
||||
const isMandatory = resolveWidgetFieldValue(component?.definition?.validation?.mandatory?.value);
|
||||
const [labelWidth, setLabelWidth] = useState(0);
|
||||
const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side';
|
||||
const [iconVisibility, setIconVisibility] = useState(false);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,12 @@ import {
|
|||
useColumnOrder,
|
||||
} from 'react-table';
|
||||
import cx from 'classnames';
|
||||
import { resolveReferences, validateWidget, determineJustifyContentValue } from '@/_helpers/utils';
|
||||
import {
|
||||
resolveReferences,
|
||||
validateWidget,
|
||||
determineJustifyContentValue,
|
||||
resolveWidgetFieldValue,
|
||||
} from '@/_helpers/utils';
|
||||
import { useExportData } from 'react-table-plugins';
|
||||
import Papa from 'papaparse';
|
||||
import { Pagination } from './Pagination';
|
||||
|
|
@ -388,11 +393,11 @@ export function Table({
|
|||
let tableData = [],
|
||||
dynamicColumn = [];
|
||||
|
||||
const useDynamicColumn = resolveReferences(component.definition.properties?.useDynamicColumn?.value, currentState);
|
||||
const useDynamicColumn = resolveWidgetFieldValue(component.definition.properties?.useDynamicColumn?.value);
|
||||
if (currentState) {
|
||||
tableData = resolveReferences(component.definition.properties.data.value, currentState, []);
|
||||
tableData = resolveWidgetFieldValue(component.definition.properties.data.value);
|
||||
dynamicColumn = useDynamicColumn
|
||||
? resolveReferences(component.definition.properties?.columnData?.value, currentState, []) ?? []
|
||||
? resolveWidgetFieldValue(component.definition.properties?.columnData?.value) ?? []
|
||||
: [];
|
||||
if (!Array.isArray(tableData)) {
|
||||
tableData = [];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import { SubCustomDragLayer } from '../SubCustomDragLayer';
|
||||
import { SubContainer } from '../SubContainer';
|
||||
import { resolveReferences, resolveWidgetFieldValue, isExpectedDataType } from '@/_helpers/utils';
|
||||
import { resolveWidgetFieldValue, isExpectedDataType } from '@/_helpers/utils';
|
||||
import { handleLowPriorityWork } from '@/_helpers/editorHelpers';
|
||||
|
||||
export const Tabs = function Tabs({
|
||||
|
|
@ -10,7 +10,6 @@ export const Tabs = function Tabs({
|
|||
width,
|
||||
height,
|
||||
containerProps,
|
||||
currentState,
|
||||
removeComponent,
|
||||
setExposedVariable,
|
||||
setExposedVariables,
|
||||
|
|
@ -25,9 +24,9 @@ export const Tabs = function Tabs({
|
|||
const disabledState = component.definition.styles?.disabledState?.value ?? false;
|
||||
const defaultTab = component.definition.properties.defaultTab.value;
|
||||
// config for tabs. Includes title
|
||||
const tabs = isExpectedDataType(resolveReferences(component.definition.properties.tabs.value, currentState), 'array');
|
||||
const tabs = isExpectedDataType(resolveWidgetFieldValue(component.definition.properties?.tabs?.value), 'array');
|
||||
let parsedTabs = tabs;
|
||||
parsedTabs = resolveWidgetFieldValue(parsedTabs, currentState);
|
||||
parsedTabs = resolveWidgetFieldValue(parsedTabs);
|
||||
const hideTabs = component.definition.properties?.hideTabs?.value ?? false;
|
||||
|
||||
//* renderOnlyActiveTab - TRUE (renders only the content of the active tab)
|
||||
|
|
@ -40,25 +39,23 @@ export const Tabs = function Tabs({
|
|||
// Highlight color - for active tab text and border
|
||||
const highlightColor = component.definition.styles?.highlightColor?.value ?? '#f44336';
|
||||
let parsedHighlightColor = highlightColor;
|
||||
parsedHighlightColor = resolveWidgetFieldValue(highlightColor, currentState);
|
||||
parsedHighlightColor = resolveWidgetFieldValue(highlightColor);
|
||||
|
||||
// Default tab
|
||||
let parsedDefaultTab = defaultTab;
|
||||
parsedDefaultTab = resolveWidgetFieldValue(parsedDefaultTab, currentState, 1);
|
||||
parsedDefaultTab = resolveWidgetFieldValue(parsedDefaultTab, 1);
|
||||
|
||||
const parsedDisabledState =
|
||||
typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState;
|
||||
typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState) : disabledState;
|
||||
|
||||
const parsedHideTabs = typeof hideTabs !== 'boolean' ? resolveWidgetFieldValue(hideTabs, currentState) : hideTabs;
|
||||
const parsedHideTabs = typeof hideTabs !== 'boolean' ? resolveWidgetFieldValue(hideTabs) : hideTabs;
|
||||
const parsedRenderOnlyActiveTab =
|
||||
typeof renderOnlyActiveTab !== 'boolean'
|
||||
? resolveWidgetFieldValue(renderOnlyActiveTab, currentState)
|
||||
: renderOnlyActiveTab;
|
||||
typeof renderOnlyActiveTab !== 'boolean' ? resolveWidgetFieldValue(renderOnlyActiveTab) : renderOnlyActiveTab;
|
||||
|
||||
let parsedWidgetVisibility = widgetVisibility;
|
||||
|
||||
try {
|
||||
parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []);
|
||||
parsedWidgetVisibility = resolveWidgetFieldValue(parsedWidgetVisibility);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
|
@ -77,7 +74,7 @@ export const Tabs = function Tabs({
|
|||
const currentTabData = parsedTabs.filter((tab) => tab.id === currentTab);
|
||||
setBgColor(currentTabData[0]?.backgroundColor ? currentTabData[0]?.backgroundColor : darkMode ? '#324156' : '#fff');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentState, currentTab]);
|
||||
}, [currentTab]);
|
||||
|
||||
function computeTabVisibility(componentId, id) {
|
||||
let tabVisibility = 'hidden';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { resolveReferences } from '@/_helpers/utils';
|
||||
import { useCurrentState } from '@/_stores/currentStateStore';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
|
||||
import * as Icons from '@tabler/icons-react';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
const tinycolor = require('tinycolor2');
|
||||
|
|
@ -45,8 +45,8 @@ export const TextInput = function TextInput({
|
|||
const [visibility, setVisibility] = useState(properties.visibility);
|
||||
const { isValid, validationError } = validate(value);
|
||||
const [showValidationError, setShowValidationError] = useState(false);
|
||||
const currentState = useCurrentState();
|
||||
const isMandatory = resolveReferences(component?.definition?.validation?.mandatory?.value, currentState);
|
||||
|
||||
const isMandatory = resolveWidgetFieldValue(component?.definition?.validation?.mandatory?.value);
|
||||
const [labelWidth, setLabelWidth] = useState(0);
|
||||
const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side';
|
||||
const [loading, setLoading] = useState(loadingState);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { ItemTypes, EditorConstants } from './editorConstants';
|
|||
import { DraggableBox } from './DraggableBox';
|
||||
import update from 'immutability-helper';
|
||||
import { componentTypes } from './WidgetManager/components';
|
||||
import { resolveReferences } from '@/_helpers/utils';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
import Comments from './Comments';
|
||||
import { commentsService } from '@/_services';
|
||||
import config from 'config';
|
||||
|
|
@ -25,7 +25,7 @@ import DragContainer from './DragContainer';
|
|||
import { compact, correctBounds } from './gridUtils';
|
||||
import { isPDFSupported } from '@/_stores/utils';
|
||||
import toast from 'react-hot-toast';
|
||||
import { isOnlyLayoutUpdate } from '@/_helpers/editorHelpers';
|
||||
import { isOnlyLayoutUpdate, handleLowPriorityWork } from '@/_helpers/editorHelpers';
|
||||
import GhostWidget from './GhostWidget';
|
||||
import { useDraggedSubContainer, useGridStore } from '@/_stores/gridStore';
|
||||
|
||||
|
|
@ -46,8 +46,8 @@ export const Container = ({
|
|||
socket,
|
||||
handleUndo,
|
||||
handleRedo,
|
||||
currentPageId,
|
||||
}) => {
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const appDefinition = useEditorStore.getState().appDefinition;
|
||||
// Dont update first time to skip
|
||||
// redundant save on app definition load
|
||||
|
|
@ -279,6 +279,10 @@ export const Container = ({
|
|||
appDefinitionChanged(newDefinition, opts);
|
||||
}
|
||||
|
||||
return () => {
|
||||
firstUpdate.current = true;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [boxes]);
|
||||
|
||||
|
|
@ -594,22 +598,26 @@ export const Container = ({
|
|||
...copyOfBoxes,
|
||||
...updatedBoxes,
|
||||
};
|
||||
const diffState = diff(boxes, newBoxes);
|
||||
|
||||
setBoxes((prev) => {
|
||||
const updatedComponentsAsperDiff = Object.keys(diffState).reduce((acc, key) => {
|
||||
const component = newBoxes[key];
|
||||
if (component) {
|
||||
acc[key] = component;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
handleLowPriorityWork(() => {
|
||||
const diffState = diff(boxes, newBoxes);
|
||||
|
||||
return {
|
||||
...prev,
|
||||
...updatedComponentsAsperDiff,
|
||||
};
|
||||
setBoxes((prev) => {
|
||||
const updatedComponentsAsperDiff = Object.keys(diffState).reduce((acc, key) => {
|
||||
const component = newBoxes[key];
|
||||
if (component) {
|
||||
acc[key] = component;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
...prev,
|
||||
...updatedComponentsAsperDiff,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
updateCanvasHeight(newBoxes);
|
||||
}
|
||||
|
||||
|
|
@ -819,7 +827,8 @@ export const Container = ({
|
|||
.map(([id, box]) => {
|
||||
const canShowInCurrentLayout =
|
||||
box.component.definition.others[currentLayout === 'mobile' ? 'showOnMobile' : 'showOnDesktop'].value;
|
||||
if (box.parent || !resolveReferences(canShowInCurrentLayout, useCurrentStateStore.getState())) {
|
||||
|
||||
if (box.parent || !resolveWidgetFieldValue(canShowInCurrentLayout)) {
|
||||
return '';
|
||||
}
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -40,15 +40,14 @@ export default function DragContainer({
|
|||
const preant = boxes.find((box) => box.id == lastDraggedEventsRef.current.events[0].target.id)?.component
|
||||
?.parent;
|
||||
// Adding the new updates to the macro task queue to unblock UI
|
||||
setTimeout(() =>
|
||||
onDrag(
|
||||
lastDraggedEventsRef.current.events.map((ev) => ({
|
||||
id: ev.target.id,
|
||||
x: ev.translate[0],
|
||||
y: ev.translate[1],
|
||||
parent: preant,
|
||||
}))
|
||||
)
|
||||
|
||||
onDrag(
|
||||
lastDraggedEventsRef.current.events.map((ev) => ({
|
||||
id: ev.target.id,
|
||||
x: ev.translate[0],
|
||||
y: ev.translate[1],
|
||||
parent: preant,
|
||||
}))
|
||||
);
|
||||
}
|
||||
if (useGridStore.getState().isGroupHandleHoverd) {
|
||||
|
|
@ -363,9 +362,9 @@ export default function DragContainer({
|
|||
resizeData.gw = _gridWidth;
|
||||
}
|
||||
// Adding the new updates to the macro task queue to unblock UI
|
||||
setTimeout(() => {
|
||||
onResizeStop([resizeData]);
|
||||
});
|
||||
// setTimeout(() => {
|
||||
// });
|
||||
onResizeStop([resizeData]);
|
||||
} catch (error) {
|
||||
console.error('ResizeEnd error ->', error);
|
||||
}
|
||||
|
|
@ -432,9 +431,9 @@ export default function DragContainer({
|
|||
|
||||
if (groupResizeDataRef.current.length) {
|
||||
// Adding the new updates to the macro task queue to unblock UI
|
||||
setTimeout(() => {
|
||||
onResizeStop([newBoxs]);
|
||||
});
|
||||
// setTimeout(() => {
|
||||
// });
|
||||
onResizeStop([newBoxs]);
|
||||
} else {
|
||||
events.forEach((ev) => {
|
||||
const currentWidget = boxes.find(({ id }) => {
|
||||
|
|
@ -562,24 +561,24 @@ export default function DragContainer({
|
|||
toast.error(`${currentWidget} is not compatible as a child component of ${parentWidget}`);
|
||||
e.target.style.transform = `translate(${left}px, ${top}px)`;
|
||||
}
|
||||
} else {
|
||||
e.target.style.transform = `translate(${Math.round(left / _gridWidth) * _gridWidth}px, ${
|
||||
Math.round(top / 10) * 10
|
||||
}px)`;
|
||||
}
|
||||
|
||||
e.target.style.transform = `translate(${Math.round(left / _gridWidth) * _gridWidth}px, ${
|
||||
Math.round(top / 10) * 10
|
||||
}px)`;
|
||||
|
||||
if (draggedOverElemId === currentParentId || isParentChangeAllowed) {
|
||||
// Adding the new updates to the macro task queue to unblock UI
|
||||
setTimeout(() =>
|
||||
onDrag([
|
||||
{
|
||||
id: e.target.id,
|
||||
x: left,
|
||||
y: Math.round(top / 10) * 10,
|
||||
parent: isParentChangeAllowed ? draggedOverElemId : undefined,
|
||||
},
|
||||
])
|
||||
);
|
||||
// setTimeout(() =>
|
||||
// );
|
||||
onDrag([
|
||||
{
|
||||
id: e.target.id,
|
||||
x: left,
|
||||
y: Math.round(top / 10) * 10,
|
||||
parent: isParentChangeAllowed ? draggedOverElemId : undefined,
|
||||
},
|
||||
]);
|
||||
}
|
||||
const box = boxes.find((box) => box.id === e.target.id);
|
||||
setTimeout(() => useEditorStore.getState().actions.setSelectedComponents([{ ...box }]));
|
||||
|
|
@ -696,31 +695,29 @@ export default function DragContainer({
|
|||
const { posRight, posLeft, posTop, posBottom } = getPositionForGroupDrag(events, parentWidth, parentHeight);
|
||||
|
||||
// Adding the new updates to the macro task queue to unblock UI
|
||||
setTimeout(() =>
|
||||
onDrag(
|
||||
events.map((ev) => {
|
||||
let posX = ev.lastEvent.translate[0];
|
||||
let posY = ev.lastEvent.translate[1];
|
||||
if (posLeft < 0) {
|
||||
posX = ev.lastEvent.translate[0] - posLeft;
|
||||
}
|
||||
if (posTop < 0) {
|
||||
posY = ev.lastEvent.translate[1] - posTop;
|
||||
}
|
||||
if (posRight < 0) {
|
||||
posX = ev.lastEvent.translate[0] + posRight;
|
||||
}
|
||||
if (posBottom < 0) {
|
||||
posY = ev.lastEvent.translate[1] + posBottom;
|
||||
}
|
||||
return {
|
||||
id: ev.target.id,
|
||||
x: posX,
|
||||
y: posY,
|
||||
parent: parentId,
|
||||
};
|
||||
})
|
||||
)
|
||||
onDrag(
|
||||
events.map((ev) => {
|
||||
let posX = ev.lastEvent.translate[0];
|
||||
let posY = ev.lastEvent.translate[1];
|
||||
if (posLeft < 0) {
|
||||
posX = ev.lastEvent.translate[0] - posLeft;
|
||||
}
|
||||
if (posTop < 0) {
|
||||
posY = ev.lastEvent.translate[1] - posTop;
|
||||
}
|
||||
if (posRight < 0) {
|
||||
posX = ev.lastEvent.translate[0] + posRight;
|
||||
}
|
||||
if (posBottom < 0) {
|
||||
posY = ev.lastEvent.translate[1] + posBottom;
|
||||
}
|
||||
return {
|
||||
id: ev.target.id,
|
||||
x: posX,
|
||||
y: posY,
|
||||
parent: parentId,
|
||||
};
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error dragging group', error);
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ const DraggableBox = React.memo(
|
|||
const configWidgetHandlerForModalComponent =
|
||||
!isSelectedComponent &&
|
||||
component.component === 'Modal' &&
|
||||
resolveWidgetFieldValue(component.definition.properties.useDefaultButton, currentState)?.value === false;
|
||||
resolveWidgetFieldValue(component.definition.properties.useDefaultButton?.value) === false;
|
||||
|
||||
const onComponentHover = useCallback(
|
||||
(id) => {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ import { HotkeysProvider } from 'react-hotkeys-hook';
|
|||
import { useResolveStore } from '@/_stores/resolverStore';
|
||||
import { dfs } from '@/_stores/handleReferenceTransactions';
|
||||
import { decimalToHex } from './editorConstants';
|
||||
import { findComponentsWithReferences, generatePath, handleLowPriorityWork } from '@/_helpers/editorHelpers';
|
||||
import { findComponentsWithReferences, handleLowPriorityWork } from '@/_helpers/editorHelpers';
|
||||
|
||||
setAutoFreeze(false);
|
||||
enablePatches();
|
||||
|
|
@ -282,9 +282,9 @@ const EditorComponent = (props) => {
|
|||
}
|
||||
|
||||
if (mounted && didAppDefinitionChanged && currentPageId) {
|
||||
const components = appDefinition?.pages[currentPageId]?.components || {};
|
||||
// const components = appDefinition?.pages[currentPageId]?.components || {};
|
||||
|
||||
computeComponentState(components);
|
||||
// computeComponentState(components);
|
||||
|
||||
if (appDiffOptions?.skipAutoSave === true || appDiffOptions?.entityReferenceUpdated === true) return;
|
||||
|
||||
|
|
@ -293,8 +293,6 @@ const EditorComponent = (props) => {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]);
|
||||
|
||||
const prevCurrentStateRef = useRef(currentState);
|
||||
|
||||
/**
|
||||
** Async updates components in batches to optimize and processing efficiency.
|
||||
* This function iterates over an array of component IDs, updating them in fixed-size batches,
|
||||
|
|
@ -634,8 +632,18 @@ const EditorComponent = (props) => {
|
|||
props.switchDarkMode(newMode);
|
||||
};
|
||||
|
||||
const handleEvent = React.useCallback((eventName, event, options) => {
|
||||
return onEvent(getEditorRef(), eventName, event, options, 'edit');
|
||||
const handleEvent = React.useCallback((eventName, events, options) => {
|
||||
const latestEvents = useAppDataStore.getState().events;
|
||||
const filteredEvents = latestEvents.filter((event) => {
|
||||
const foundEvent = events.find((e) => e.id === event.id);
|
||||
return foundEvent && foundEvent.name === eventName;
|
||||
});
|
||||
|
||||
try {
|
||||
return onEvent(getEditorRef(), eventName, filteredEvents, options, 'edit');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
|
|
@ -743,12 +751,12 @@ const EditorComponent = (props) => {
|
|||
|
||||
useCurrentStateStore.getState().actions.setCurrentState({
|
||||
page: currentpageData,
|
||||
}),
|
||||
updateEditorState({
|
||||
isLoading: false,
|
||||
appDefinition: appJson,
|
||||
isUpdatingEditorStateInProcess: false,
|
||||
});
|
||||
});
|
||||
updateEditorState({
|
||||
isLoading: false,
|
||||
appDefinition: appJson,
|
||||
isUpdatingEditorStateInProcess: false,
|
||||
});
|
||||
|
||||
updateState({ components: appJson.pages[homePageId]?.components });
|
||||
|
||||
|
|
@ -765,129 +773,9 @@ const EditorComponent = (props) => {
|
|||
await fetchDataSources(data.editing_version?.id),
|
||||
await fetchDataQueries(data.editing_version?.id, true, true),
|
||||
])
|
||||
.then(() => {
|
||||
useCurrentStateStore.getState().actions.setEditorReady(true);
|
||||
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components;
|
||||
|
||||
const referenceManager = useResolveStore.getState().referenceMapper;
|
||||
|
||||
const newComponents = Object.keys(currentComponents).map((componentId) => {
|
||||
const component = currentComponents[componentId];
|
||||
|
||||
if (!referenceManager.get(componentId)) {
|
||||
return {
|
||||
id: componentId,
|
||||
name: component.component.name,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
useResolveStore.getState().actions.addEntitiesToMap(newComponents);
|
||||
})
|
||||
.then(() => {
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components;
|
||||
let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries));
|
||||
let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events));
|
||||
|
||||
const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])
|
||||
?.map((entity) => {
|
||||
if (entity && isValidUUID(entity)) {
|
||||
return entity;
|
||||
}
|
||||
})
|
||||
?.filter((e) => e !== undefined);
|
||||
|
||||
const entityReferencesInQueryoOptions = findAllEntityReferences(dataQueries, [])
|
||||
?.map((entity) => {
|
||||
if (entity && isValidUUID(entity)) {
|
||||
return entity;
|
||||
}
|
||||
})
|
||||
?.filter((e) => e !== undefined);
|
||||
|
||||
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])
|
||||
?.map((entity) => {
|
||||
if (entity && isValidUUID(entity)) {
|
||||
return entity;
|
||||
}
|
||||
})
|
||||
?.filter((e) => e !== undefined);
|
||||
|
||||
const manager = useResolveStore.getState().referenceMapper;
|
||||
|
||||
if (
|
||||
Array.isArray(entityReferencesInComponentDefinitions) &&
|
||||
entityReferencesInComponentDefinitions?.length > 0
|
||||
) {
|
||||
let newComponentDefinition = JSON.parse(JSON.stringify(currentComponents));
|
||||
|
||||
entityReferencesInComponentDefinitions.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newComponentDefinition = dfs(newComponentDefinition, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
const newAppDefinition = produce(appJson, (draft) => {
|
||||
draft.pages[homePageId].components = newComponentDefinition;
|
||||
});
|
||||
|
||||
updateEditorState({
|
||||
isUpdatingEditorStateInProcess: false,
|
||||
appDefinition: newAppDefinition,
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(entityReferencesInQueryoOptions) && entityReferencesInQueryoOptions?.length > 0) {
|
||||
let newQueryOptions = {};
|
||||
dataQueries?.forEach((query) => {
|
||||
newQueryOptions[query.id] = query.options;
|
||||
``;
|
||||
});
|
||||
|
||||
entityReferencesInQueryoOptions.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newQueryOptions = dfs(newQueryOptions, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
dataQueries = dataQueries.map((query) => {
|
||||
const queryId = query.id;
|
||||
const dqOptions = newQueryOptions[queryId];
|
||||
|
||||
return {
|
||||
...query,
|
||||
options: dqOptions,
|
||||
};
|
||||
});
|
||||
|
||||
useDataQueriesStore.getState().actions.setDataQueries(dataQueries, 'mappingUpdate');
|
||||
}
|
||||
|
||||
if (Array.isArray(entityReferencesInEvents) && entityReferencesInEvents?.length > 0) {
|
||||
let newEvents = JSON.parse(JSON.stringify(allEvents));
|
||||
|
||||
entityReferencesInEvents.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newEvents = dfs(newEvents, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
updateState({
|
||||
events: newEvents,
|
||||
});
|
||||
}
|
||||
.then(async () => {
|
||||
await onEditorLoad(appJson, homePageId, versionSwitched);
|
||||
updateEntityReferences(appJson, homePageId);
|
||||
})
|
||||
.finally(async () => {
|
||||
const currentPageEvents = data.events.filter(
|
||||
|
|
@ -927,6 +815,9 @@ const EditorComponent = (props) => {
|
|||
updateEditorState({
|
||||
isLoading: true,
|
||||
});
|
||||
useCurrentStateStore.getState().actions.setCurrentState({});
|
||||
useCurrentStateStore.getState().actions.setEditorReady(false);
|
||||
useResolveStore.getState().actions.resetStore();
|
||||
|
||||
callBack(appData, null, true);
|
||||
initComponentVersioning();
|
||||
|
|
@ -1093,7 +984,7 @@ const EditorComponent = (props) => {
|
|||
updateEditorState({
|
||||
isUpdatingEditorStateInProcess: false,
|
||||
});
|
||||
} else if (!isEmpty(editingVersion)) {
|
||||
} else if (!isEmpty(editingVersion) && !isEmpty(appDiffOptions) && appDefinition) {
|
||||
//! The computeComponentPropertyDiff function manages the calculation of differences in table columns by requiring complete column data. Without this complete data, the resulting JSON structure may be incorrect.
|
||||
const paramDiff = computeComponentPropertyDiff(appDefinitionDiff, appDefinition, appDiffOptions);
|
||||
const updateDiff = computeAppDiff(paramDiff, currentPageId, appDiffOptions, currentLayout);
|
||||
|
|
@ -1131,24 +1022,26 @@ const EditorComponent = (props) => {
|
|||
}
|
||||
|
||||
//Todo: Move this to a separate function or as a middleware of the api to createing a component
|
||||
if (updateDiff?.type === 'components' && updateDiff?.operation === 'create') {
|
||||
const componentsFromCurrentState = getCurrentState().components;
|
||||
const newComponentIds = Object.keys(updateDiff?.updateDiff);
|
||||
const newComponentsExposedData = {};
|
||||
const componentEntityArray = [];
|
||||
Object.values(componentsFromCurrentState).filter((component) => {
|
||||
if (newComponentIds.includes(component.id)) {
|
||||
const componentName = updateDiff?.updateDiff[component.id]?.name;
|
||||
newComponentsExposedData[componentName] = component;
|
||||
componentEntityArray.push({ id: component.id, name: componentName });
|
||||
}
|
||||
});
|
||||
handleLowPriorityWork(() => {
|
||||
if (updateDiff?.type === 'components' && updateDiff?.operation === 'create') {
|
||||
const componentsFromCurrentState = getCurrentState().components;
|
||||
const newComponentIds = Object.keys(updateDiff?.updateDiff);
|
||||
const newComponentsExposedData = {};
|
||||
const componentEntityArray = [];
|
||||
Object.values(componentsFromCurrentState).filter((component) => {
|
||||
if (newComponentIds.includes(component.id)) {
|
||||
const componentName = updateDiff?.updateDiff[component.id]?.name;
|
||||
newComponentsExposedData[componentName] = component;
|
||||
componentEntityArray.push({ id: component.id, name: componentName });
|
||||
}
|
||||
});
|
||||
|
||||
useResolveStore.getState().actions.addEntitiesToMap(componentEntityArray);
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
components: newComponentsExposedData,
|
||||
});
|
||||
}
|
||||
useResolveStore.getState().actions.addEntitiesToMap(componentEntityArray);
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
components: newComponentsExposedData,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
updateDiff?.type === 'components' &&
|
||||
|
|
@ -1199,7 +1092,7 @@ const EditorComponent = (props) => {
|
|||
};
|
||||
|
||||
const realtimeSave = debounce(appDefinitionChanged, 100);
|
||||
const autoSave = debounce(saveEditingVersion, 150);
|
||||
const autoSave = saveEditingVersion;
|
||||
|
||||
function handlePaths(prevPatch, path = [], appJSON) {
|
||||
const paths = [...path];
|
||||
|
|
@ -1488,6 +1381,117 @@ const EditorComponent = (props) => {
|
|||
}
|
||||
};
|
||||
|
||||
const onEditorLoad = (appJson, pageId, isPageSwitchOrVersionSwitch = false) => {
|
||||
useCurrentStateStore.getState().actions.setEditorReady(true);
|
||||
const currentComponents = appJson?.pages?.[pageId]?.components;
|
||||
|
||||
const referenceManager = useResolveStore.getState().referenceMapper;
|
||||
|
||||
const newComponents = Object.keys(currentComponents).map((componentId) => {
|
||||
const component = currentComponents[componentId];
|
||||
|
||||
if (isPageSwitchOrVersionSwitch || !referenceManager.get(componentId)) {
|
||||
return {
|
||||
id: componentId,
|
||||
name: component.component.name,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
useResolveStore.getState().actions.addEntitiesToMap(newComponents);
|
||||
};
|
||||
|
||||
const updateEntityReferences = (appJson, pageId) => {
|
||||
const currentComponents = appJson?.pages?.[pageId]?.components;
|
||||
|
||||
let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries));
|
||||
let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events));
|
||||
|
||||
const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const entityReferencesInQueryOptions = findAllEntityReferences(dataQueries, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const manager = useResolveStore.getState().referenceMapper;
|
||||
|
||||
if (Array.isArray(entityReferencesInComponentDefinitions) && entityReferencesInComponentDefinitions?.length > 0) {
|
||||
let newComponentDefinition = JSON.parse(JSON.stringify(currentComponents));
|
||||
|
||||
entityReferencesInComponentDefinitions.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newComponentDefinition = dfs(newComponentDefinition, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
const newAppDefinition = produce(appJson, (draft) => {
|
||||
draft.pages[pageId].components = newComponentDefinition;
|
||||
});
|
||||
|
||||
handleLowPriorityWork(() => {
|
||||
updateEditorState({
|
||||
isUpdatingEditorStateInProcess: false,
|
||||
appDefinition: newAppDefinition,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(entityReferencesInQueryOptions) && entityReferencesInQueryOptions?.length > 0) {
|
||||
let newQueryOptions = {};
|
||||
dataQueries?.forEach((query) => {
|
||||
newQueryOptions[query.id] = query.options;
|
||||
``;
|
||||
});
|
||||
|
||||
entityReferencesInQueryOptions.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newQueryOptions = dfs(newQueryOptions, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
dataQueries = dataQueries.map((query) => {
|
||||
const queryId = query.id;
|
||||
const dqOptions = newQueryOptions[queryId];
|
||||
|
||||
return {
|
||||
...query,
|
||||
options: dqOptions,
|
||||
};
|
||||
});
|
||||
|
||||
useDataQueriesStore.getState().actions.setDataQueries(dataQueries, 'mappingUpdate');
|
||||
}
|
||||
|
||||
if (Array.isArray(entityReferencesInEvents) && entityReferencesInEvents?.length > 0) {
|
||||
let newEvents = JSON.parse(JSON.stringify(allEvents));
|
||||
|
||||
entityReferencesInEvents.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newEvents = dfs(newEvents, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
updateState({
|
||||
events: newEvents,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const removeComponents = () => {
|
||||
const selectedComponents = useEditorStore.getState()?.selectedComponents;
|
||||
if (!isVersionReleased && selectedComponents?.length > 1) {
|
||||
|
|
@ -1602,7 +1606,9 @@ const EditorComponent = (props) => {
|
|||
});
|
||||
};
|
||||
|
||||
const switchPage = (pageId, queryParams = []) => {
|
||||
const switchPage = async (pageId, queryParams = []) => {
|
||||
useCurrentStateStore.getState().actions.setEditorReady(false);
|
||||
useResolveStore.getState().actions.resetStore();
|
||||
// This are fetched from store to handle runQueriesOnAppLoad
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const appDefinition = useEditorStore.getState().appDefinition;
|
||||
|
|
@ -1629,7 +1635,13 @@ const EditorComponent = (props) => {
|
|||
...currentState.globals,
|
||||
urlparams: JSON.parse(JSON.stringify(queryString.parse(queryParamsString))),
|
||||
};
|
||||
|
||||
useCurrentStateStore.getState().actions.setCurrentState({ globals, page });
|
||||
useResolveStore.getState().actions.pageSwitched(true);
|
||||
|
||||
await onEditorLoad(appDefinition, pageId, true);
|
||||
updateEntityReferences(appDefinition, pageId);
|
||||
useResolveStore.getState().actions.updateJSHints();
|
||||
|
||||
setCurrentPageId(pageId);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,18 +3,13 @@ import Selecto from 'react-selecto';
|
|||
import { useEditorStore, EMPTY_ARRAY } from '@/_stores/editorStore';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
const EditorSelecto = ({
|
||||
selectionRef,
|
||||
canvasContainerRef,
|
||||
currentPageId,
|
||||
setSelectedComponent,
|
||||
appDefinition,
|
||||
selectionDragRef,
|
||||
}) => {
|
||||
const { setSelectionInProgress, setSelectedComponents } = useEditorStore(
|
||||
const EditorSelecto = ({ selectionRef, canvasContainerRef, setSelectedComponent, selectionDragRef }) => {
|
||||
const { setSelectionInProgress, setSelectedComponents, currentPageId, appDefinition } = useEditorStore(
|
||||
(state) => ({
|
||||
setSelectionInProgress: state?.actions?.setSelectionInProgress,
|
||||
setSelectedComponents: state?.actions?.setSelectedComponents,
|
||||
currentPageId: state?.currentPageId,
|
||||
appDefinition: state?.appDefinition,
|
||||
}),
|
||||
shallow
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { renderElement } from '../Utils';
|
||||
import { EventManager } from '@/Editor/Inspector/EventManager';
|
||||
import Accordion from '@/_ui/Accordion';
|
||||
import { resolveReferences } from '@/_helpers/utils';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
import CodeHinter from '@/Editor/CodeEditor';
|
||||
|
||||
class Chart extends React.Component {
|
||||
|
|
@ -74,9 +74,8 @@ class Chart extends React.Component {
|
|||
|
||||
const jsonDescription = this.props.component.component.definition.properties.jsonDescription;
|
||||
|
||||
const plotFromJson = resolveReferences(
|
||||
this.props.component.component.definition.properties.plotFromJson?.value,
|
||||
currentState
|
||||
const plotFromJson = resolveWidgetFieldValue(
|
||||
this.props.component.component.definition.properties.plotFromJson?.value
|
||||
);
|
||||
const chartType = this.props.component.component.definition.properties.type.value;
|
||||
|
||||
|
|
|
|||
|
|
@ -108,10 +108,10 @@ export const EventManager = ({
|
|||
return { name: action.name, value: action.id };
|
||||
});
|
||||
|
||||
let checkIfClicksAreInsideOf = document.querySelector('#cm-complete-0');
|
||||
let checkIfClicksAreInsideOf = document.querySelector('.cm-completionListIncompleteBottom');
|
||||
// Listen for click events on body
|
||||
if (checkIfClicksAreInsideOf) {
|
||||
document.body.addEventListener('click', function (event) {
|
||||
document.body.addEventListener('mousedown', function (event) {
|
||||
if (checkIfClicksAreInsideOf.contains(event.target)) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ const ParameterDetails = ({ darkMode, onSubmit, isEdit, name, defaultValue, onRe
|
|||
if (
|
||||
showModal &&
|
||||
event.target.closest('#parameter-form-popover') === null &&
|
||||
event.target.closest('#cm-complete-0') === null
|
||||
event.target.closest('.cm-completionListIncompleteBottom') === null
|
||||
) {
|
||||
closeMenu();
|
||||
}
|
||||
};
|
||||
|
||||
if (showModal) {
|
||||
document.addEventListener('mouseup', handleClickOutside);
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
} else {
|
||||
document.removeEventListener('mouseup', handleClickOutside);
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
}
|
||||
return () => {
|
||||
document.removeEventListener('mouseup', handleClickOutside);
|
||||
document.removeEventListener('click', handleClickOutside);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showModal]);
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ import update from 'immutability-helper';
|
|||
import _, { isEmpty } from 'lodash';
|
||||
import { componentTypes } from './WidgetManager/components';
|
||||
import { addNewWidgetToTheEditor, onComponentOptionChanged, onComponentOptionsChanged } from '@/_helpers/appUtils';
|
||||
import { resolveReferences } from '@/_helpers/utils';
|
||||
import { resolveWidgetFieldValue } from '@/_helpers/utils';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { restrictedWidgetsObj } from '@/Editor/WidgetManager/restrictedWidgetsConfig';
|
||||
import { useCurrentState } from '@/_stores/currentStateStore';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { useMounted } from '@/_hooks/use-mount';
|
||||
|
||||
import { useEditorStore } from '@/_stores/editorStore';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { diff } from 'deep-object-diff';
|
||||
|
|
@ -450,7 +450,7 @@ export const SubContainer = ({
|
|||
const canShowInCurrentLayout =
|
||||
box.component.definition.others[currentLayout === 'mobile' ? 'showOnMobile' : 'showOnDesktop'].value;
|
||||
|
||||
if (box.component.parent && resolveReferences(canShowInCurrentLayout, currentState)) {
|
||||
if (box.component.parent && resolveWidgetFieldValue(canShowInCurrentLayout)) {
|
||||
return (
|
||||
<SubWidgetWrapper
|
||||
isResizing={resizingComponentId === key}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ import {
|
|||
import queryString from 'query-string';
|
||||
import ViewerLogoIcon from './Icons/viewer-logo.svg';
|
||||
import { DataSourceTypes } from './DataSourceManager/SourceComponents';
|
||||
import { resolveReferences, isQueryRunnable, setWindowTitle, pageTitles } from '@/_helpers/utils';
|
||||
import { resolveReferences, isQueryRunnable, setWindowTitle, pageTitles, isValidUUID } from '@/_helpers/utils';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import _ from 'lodash';
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import Spinner from '@/_ui/Spinner';
|
||||
import { withRouter } from '@/_hoc/withRouter';
|
||||
import { useEditorStore } from '@/_stores/editorStore';
|
||||
import { flushComponentsToRender, useEditorActions, useEditorStore } from '@/_stores/editorStore';
|
||||
import { setCookie } from '@/_helpers/cookie';
|
||||
import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
|
||||
import { useCurrentStateStore } from '@/_stores/currentStateStore';
|
||||
|
|
@ -46,6 +46,12 @@ import ViewerSidebarNavigation from './Viewer/ViewerSidebarNavigation';
|
|||
import MobileHeader from './Viewer/MobileHeader';
|
||||
import DesktopHeader from './Viewer/DesktopHeader';
|
||||
import './Viewer/viewer.scss';
|
||||
import { useResolveStore } from '@/_stores/resolverStore';
|
||||
import { findComponentsWithReferences } from '@/_helpers/editorHelpers';
|
||||
import { findAllEntityReferences } from '@/_stores/utils';
|
||||
import { dfs } from '@/_stores/handleReferenceTransactions';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import produce from 'immer';
|
||||
|
||||
class ViewerComponent extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
@ -166,6 +172,9 @@ class ViewerComponent extends React.Component {
|
|||
const currentPage = pages.find((page) => page.id === currentPageId);
|
||||
|
||||
useDataQueriesStore.getState().actions.setDataQueries(dataQueries);
|
||||
useEditorStore.getState().actions.updateEditorState({
|
||||
currentPageId: currentPageId,
|
||||
});
|
||||
this.props.setCurrentState({
|
||||
queries: queryState,
|
||||
components: {},
|
||||
|
|
@ -189,6 +198,25 @@ class ViewerComponent extends React.Component {
|
|||
});
|
||||
useEditorStore.getState().actions.toggleCurrentLayout(this.props?.currentLayout == 'mobile' ? 'mobile' : 'desktop');
|
||||
this.props.updateState({ events: data.events ?? [] });
|
||||
const currentPageComponents = appDefData?.pages[currentPageId]?.components;
|
||||
|
||||
if (currentPageComponents && !_.isEmpty(currentPageComponents)) {
|
||||
const referenceManager = useResolveStore.getState().referenceMapper;
|
||||
|
||||
const newComponents = Object.keys(currentPageComponents).map((componentId) => {
|
||||
const component = currentPageComponents[componentId];
|
||||
|
||||
if (!referenceManager.get(componentId)) {
|
||||
return {
|
||||
id: componentId,
|
||||
name: component.component.name,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
useResolveStore.getState().actions.addEntitiesToMap(newComponents);
|
||||
}
|
||||
|
||||
this.setState(
|
||||
{
|
||||
currentUser,
|
||||
|
|
@ -206,10 +234,102 @@ class ViewerComponent extends React.Component {
|
|||
events: data.events ?? [],
|
||||
},
|
||||
() => {
|
||||
const components = appDefData?.pages[currentPageId]?.components || {};
|
||||
// const components = appDefData?.pages[currentPageId]?.components || {};
|
||||
|
||||
computeComponentState(components).then(async () => {
|
||||
const appJson = JSON.parse(JSON.stringify(appDefData));
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components;
|
||||
let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries));
|
||||
let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events));
|
||||
|
||||
const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const entityReferencesInQueryOptions = findAllEntityReferences(dataQueries, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const manager = useResolveStore.getState().referenceMapper;
|
||||
|
||||
if (
|
||||
Array.isArray(entityReferencesInComponentDefinitions) &&
|
||||
entityReferencesInComponentDefinitions?.length > 0
|
||||
) {
|
||||
let newComponentDefinition = JSON.parse(JSON.stringify(currentComponents));
|
||||
|
||||
entityReferencesInComponentDefinitions.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newComponentDefinition = dfs(newComponentDefinition, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
const newAppDefinition = produce(appJson, (draft) => {
|
||||
draft.pages[homePageId].components = newComponentDefinition;
|
||||
});
|
||||
|
||||
useEditorStore.getState().actions.updateEditorState({
|
||||
isUpdatingEditorStateInProcess: false,
|
||||
appDefinition: newAppDefinition,
|
||||
});
|
||||
}
|
||||
|
||||
if (Array.isArray(entityReferencesInQueryOptions) && entityReferencesInQueryOptions?.length > 0) {
|
||||
let newQueryOptions = {};
|
||||
dataQueries?.forEach((query) => {
|
||||
newQueryOptions[query.id] = query.options;
|
||||
``;
|
||||
});
|
||||
|
||||
entityReferencesInQueryOptions.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newQueryOptions = dfs(newQueryOptions, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
dataQueries = dataQueries.map((query) => {
|
||||
const queryId = query.id;
|
||||
const dqOptions = newQueryOptions[queryId];
|
||||
|
||||
return {
|
||||
...query,
|
||||
options: dqOptions,
|
||||
};
|
||||
});
|
||||
|
||||
useDataQueriesStore.getState().actions.setDataQueries(dataQueries, 'mappingUpdate');
|
||||
}
|
||||
|
||||
if (Array.isArray(entityReferencesInEvents) && entityReferencesInEvents?.length > 0) {
|
||||
let newEvents = JSON.parse(JSON.stringify(allEvents));
|
||||
|
||||
entityReferencesInEvents.forEach((entity) => {
|
||||
const entityrefExists = manager.has(entity);
|
||||
|
||||
if (entityrefExists) {
|
||||
const value = manager.get(entity);
|
||||
newEvents = dfs(newEvents, entity, value);
|
||||
}
|
||||
});
|
||||
|
||||
this.props.updateState({
|
||||
events: newEvents,
|
||||
});
|
||||
}
|
||||
|
||||
computeComponentState(currentComponents).then(async () => {
|
||||
this.setState({ initialComputationOfStateDone: true, defaultComponentStateComputed: true });
|
||||
useCurrentStateStore.getState().actions.setEditorReady(true);
|
||||
this.runQueries(dataQueries);
|
||||
|
||||
const currentPageEvents = this.state.events.filter(
|
||||
|
|
@ -770,14 +890,52 @@ class ViewerComponent extends React.Component {
|
|||
}
|
||||
const withStore = (Component) => (props) => {
|
||||
const currentState = useCurrentStateStore();
|
||||
const { currentLayout, queryConfirmationList } = useEditorStore(
|
||||
const { currentLayout, queryConfirmationList, currentPageId } = useEditorStore(
|
||||
(state) => ({
|
||||
currentLayout: state?.currentLayout,
|
||||
queryConfirmationList: state?.queryConfirmationList,
|
||||
currentPageId: state?.currentPageId,
|
||||
}),
|
||||
shallow
|
||||
);
|
||||
|
||||
const { updateComponentsNeedsUpdateOnNextRender } = useEditorActions();
|
||||
const { updateState } = useAppDataActions();
|
||||
|
||||
const lastUpdatedRef = useResolveStore((state) => state.lastUpdatedRefs, shallow);
|
||||
|
||||
async function batchUpdateComponents(componentIds) {
|
||||
if (componentIds.length === 0) return;
|
||||
|
||||
let updatedComponentIds = [];
|
||||
|
||||
for (let i = 0; i < componentIds.length; i += 10) {
|
||||
const batch = componentIds.slice(i, i + 10);
|
||||
batch.forEach((id) => {
|
||||
updatedComponentIds.push(id);
|
||||
});
|
||||
|
||||
updateComponentsNeedsUpdateOnNextRender(batch);
|
||||
// Delay to allow UI to process
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
|
||||
// Flush only updated components
|
||||
flushComponentsToRender(updatedComponentIds);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (lastUpdatedRef.length > 0) {
|
||||
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components || {};
|
||||
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, lastUpdatedRef);
|
||||
|
||||
if (componentIdsWithReferences.length > 0) {
|
||||
batchUpdateComponents(componentIdsWithReferences);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [lastUpdatedRef]);
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -604,6 +604,9 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
|
|||
const value = resolveReferences(event.value, getCurrentState(), undefined, customVariables);
|
||||
const customAppVariables = { ...getCurrentState().variables };
|
||||
customAppVariables[key] = value;
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
variables: customAppVariables,
|
||||
});
|
||||
return useCurrentStateStore.getState().actions.setCurrentState({
|
||||
variables: customAppVariables,
|
||||
});
|
||||
|
|
@ -619,6 +622,7 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
|
|||
const key = resolveReferences(event.key, getCurrentState(), undefined, customVariables);
|
||||
const customAppVariables = { ...getCurrentState().variables };
|
||||
delete customAppVariables[key];
|
||||
// useResolveStore.getState().actions.removeAppSuggestions(key);
|
||||
return useCurrentStateStore.getState().actions.setCurrentState({
|
||||
variables: customAppVariables,
|
||||
});
|
||||
|
|
@ -631,6 +635,9 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
|
|||
...getCurrentState().page.variables,
|
||||
[key]: value,
|
||||
};
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
variables: customPageVariables,
|
||||
});
|
||||
return useCurrentStateStore.getState().actions.setCurrentState({
|
||||
page: {
|
||||
...getCurrentState().page,
|
||||
|
|
@ -650,6 +657,7 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
|
|||
case 'unset-page-variable': {
|
||||
const key = resolveReferences(event.key, getCurrentState(), undefined, customVariables);
|
||||
const customPageVariables = _.omit(getCurrentState().page.variables, key);
|
||||
// useResolveStore.getState().actions.removeAppSuggestions(key);
|
||||
return useCurrentStateStore.getState().actions.setCurrentState({
|
||||
page: {
|
||||
...getCurrentState().page,
|
||||
|
|
@ -1292,14 +1300,16 @@ export function runQuery(
|
|||
},
|
||||
});
|
||||
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
queries: {
|
||||
[queryName]: {
|
||||
data: finalData,
|
||||
isLoading: false,
|
||||
if (mode === 'edit') {
|
||||
useResolveStore.getState().actions.addAppSuggestions({
|
||||
queries: {
|
||||
[queryName]: {
|
||||
data: finalData,
|
||||
isLoading: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const basePath = `queries.${queryName}`;
|
||||
|
||||
|
|
@ -2039,7 +2049,7 @@ export const buildAppDefinition = (data) => {
|
|||
_.unset(editingVersion, 'id');
|
||||
|
||||
const pages = data.pages.reduce((acc, page) => {
|
||||
const currentComponents = buildComponentMetaDefinition(_.cloneDeep(page?.components));
|
||||
const currentComponents = buildComponentMetaDefinition(page?.components);
|
||||
|
||||
page.components = currentComponents;
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,11 @@ export function findComponentsWithReferences(components, changedCurrentState) {
|
|||
return componentIdsWithReferences;
|
||||
}
|
||||
|
||||
export function handleLowPriorityWork(callback, timeout = null) {
|
||||
export function handleLowPriorityWork(callback, timeout = null, immediate = false) {
|
||||
if (immediate) {
|
||||
callback();
|
||||
}
|
||||
|
||||
const options = timeout ? { timeout } : {};
|
||||
window.requestIdleCallback(callback, options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import { toast } from 'react-hot-toast';
|
|||
import { authenticationService } from '@/_services/authentication.service';
|
||||
|
||||
import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
|
||||
import { getCurrentState } from '@/_stores/currentStateStore';
|
||||
import { getCurrentState, useCurrentState } from '@/_stores/currentStateStore';
|
||||
import { getWorkspaceIdOrSlugFromURL, getSubpath, returnWorkspaceIdIfNeed } from './routes';
|
||||
import { getCookie, eraseCookie } from '@/_helpers/cookie';
|
||||
import { staticDataSources } from '@/Editor/QueryManager/constants';
|
||||
import { resolveReferences as newResolver } from '@/Editor/CodeEditor/utils';
|
||||
import { useResolveStore } from '@/_stores/resolverStore';
|
||||
|
||||
export function findProp(obj, prop, defval) {
|
||||
if (typeof defval === 'undefined') defval = null;
|
||||
|
|
@ -324,10 +326,22 @@ export const serializeNestedObjectToQueryParams = function (obj, prefix) {
|
|||
return str.join('&');
|
||||
};
|
||||
|
||||
export function resolveWidgetFieldValue(prop, state, _default = [], customResolveObjects = {}) {
|
||||
export function resolveWidgetFieldValue(prop, _default = [], customResolveObjects = {}) {
|
||||
const widgetFieldValue = prop;
|
||||
|
||||
const isStoreAndEditorReady = useResolveStore.getState().updateStoreState && useCurrentState.getState().isEditorReady;
|
||||
|
||||
try {
|
||||
if (isStoreAndEditorReady) {
|
||||
const [_, _error, resolveValue] = newResolver(widgetFieldValue?.value);
|
||||
|
||||
if (_error) {
|
||||
return _default;
|
||||
}
|
||||
|
||||
return resolveValue;
|
||||
}
|
||||
const state = getCurrentState();
|
||||
return resolveReferences(widgetFieldValue, state, _default, customResolveObjects);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
|
|
@ -347,7 +361,7 @@ export function validateWidget({ validationObject, widgetValue, currentState, cu
|
|||
const maxValue = validationObject?.maxValue?.value;
|
||||
const customRule = validationObject?.customRule?.value;
|
||||
const mandatory = validationObject?.mandatory?.value;
|
||||
const validationRegex = resolveWidgetFieldValue(regex, currentState, '', customResolveObjects);
|
||||
const validationRegex = resolveWidgetFieldValue(regex, '', customResolveObjects);
|
||||
const re = new RegExp(validationRegex, 'g');
|
||||
|
||||
if (!re.test(widgetValue)) {
|
||||
|
|
@ -357,7 +371,7 @@ export function validateWidget({ validationObject, widgetValue, currentState, cu
|
|||
};
|
||||
}
|
||||
|
||||
const resolvedMinLength = resolveWidgetFieldValue(minLength, currentState, 0, customResolveObjects);
|
||||
const resolvedMinLength = resolveWidgetFieldValue(minLength, 0, customResolveObjects);
|
||||
if ((widgetValue || '').length < parseInt(resolvedMinLength)) {
|
||||
return {
|
||||
isValid: false,
|
||||
|
|
@ -365,7 +379,7 @@ export function validateWidget({ validationObject, widgetValue, currentState, cu
|
|||
};
|
||||
}
|
||||
|
||||
const resolvedMaxLength = resolveWidgetFieldValue(maxLength, currentState, undefined, customResolveObjects);
|
||||
const resolvedMaxLength = resolveWidgetFieldValue(maxLength, undefined, customResolveObjects);
|
||||
if (resolvedMaxLength !== undefined) {
|
||||
if ((widgetValue || '').length > parseInt(resolvedMaxLength)) {
|
||||
return {
|
||||
|
|
@ -375,7 +389,7 @@ export function validateWidget({ validationObject, widgetValue, currentState, cu
|
|||
}
|
||||
}
|
||||
|
||||
const resolvedMinValue = resolveWidgetFieldValue(minValue, currentState, undefined, customResolveObjects);
|
||||
const resolvedMinValue = resolveWidgetFieldValue(minValue, undefined, customResolveObjects);
|
||||
if (resolvedMinValue !== undefined) {
|
||||
if (widgetValue === undefined || widgetValue < parseFloat(resolvedMinValue)) {
|
||||
return {
|
||||
|
|
@ -395,12 +409,12 @@ export function validateWidget({ validationObject, widgetValue, currentState, cu
|
|||
}
|
||||
}
|
||||
|
||||
const resolvedCustomRule = resolveWidgetFieldValue(customRule, currentState, false, customResolveObjects);
|
||||
const resolvedCustomRule = resolveWidgetFieldValue(customRule, false, customResolveObjects);
|
||||
if (typeof resolvedCustomRule === 'string' && resolvedCustomRule !== '') {
|
||||
return { isValid: false, validationError: resolvedCustomRule };
|
||||
}
|
||||
|
||||
const resolvedMandatory = resolveWidgetFieldValue(mandatory, currentState, false, customResolveObjects);
|
||||
const resolvedMandatory = resolveWidgetFieldValue(mandatory, false, customResolveObjects);
|
||||
|
||||
if (resolvedMandatory == true) {
|
||||
if (!widgetValue) {
|
||||
|
|
|
|||
|
|
@ -3,15 +3,8 @@ import { useRef, useEffect } from 'react';
|
|||
function useRenderCount(componentName) {
|
||||
const renderCountRef = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log(`--Component ${componentName} rendered unmounting ${renderCountRef.current} times.`);
|
||||
};
|
||||
}, []);
|
||||
|
||||
renderCountRef.current++;
|
||||
|
||||
console.log(`CountingRender- Component ${componentName} rendered ${renderCountRef.current} times.`);
|
||||
return renderCountRef.current;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ export const useAppDataStore = create(
|
|||
updateEditingVersion: (version) => set(() => ({ editingVersion: version })),
|
||||
updateApps: (apps) => set(() => ({ apps: apps })),
|
||||
updateState: (state) => set((prev) => ({ ...prev, ...state })),
|
||||
|
||||
updateAppDefinitionDiff: (appDefinitionDiff) => set(() => ({ appDefinitionDiff: appDefinitionDiff })),
|
||||
updateAppVersion: (appId, versionId, pageId, appDefinitionDiff, isUserSwitchedVersion = false) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -111,13 +110,10 @@ export const useAppDataStore = create(
|
|||
}
|
||||
});
|
||||
|
||||
const entityReferencesInEvents = findAllEntityReferences(updatedEvents, [])
|
||||
?.map((entity) => {
|
||||
if (entity && isValidUUID(entity)) {
|
||||
return entity;
|
||||
}
|
||||
})
|
||||
?.filter((e) => e !== undefined);
|
||||
const entityReferencesInEvents = findAllEntityReferences(updatedEvents, [])?.filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
const manager = useResolveStore.getState().referenceMapper;
|
||||
let newEvents = JSON.parse(JSON.stringify(updatedEvents));
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@ import { shallow } from 'zustand/shallow';
|
|||
import { create, zustandDevTools } from './utils';
|
||||
import _, { debounce, merge, omit } from 'lodash';
|
||||
import { useResolveStore } from './resolverStore';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { diff } from 'deep-object-diff';
|
||||
import { useEditorStore } from './editorStore';
|
||||
import { handleLowPriorityWork } from '@/_helpers/editorHelpers';
|
||||
|
||||
const initialState = {
|
||||
|
|
@ -88,19 +85,26 @@ useCurrentStateStore.subscribe((state) => {
|
|||
const isStoreIntialized = useResolveStore.getState().storeReady;
|
||||
|
||||
if (!isStoreIntialized) {
|
||||
handleLowPriorityWork(() => {
|
||||
useResolveStore.getState().actions.updateAppSuggestions({
|
||||
queries: state.queries,
|
||||
components: state.components,
|
||||
globals: state.globals,
|
||||
page: state.page,
|
||||
variables: state.variables,
|
||||
client: state.client,
|
||||
server: state.server,
|
||||
constants: state.constants,
|
||||
});
|
||||
});
|
||||
console.log('Resolver store initialized with current state.');
|
||||
const isPageSwitched = useResolveStore.getState().isPageSwitched;
|
||||
|
||||
handleLowPriorityWork(
|
||||
() => {
|
||||
useResolveStore.getState().actions.updateAppSuggestions({
|
||||
queries: state.queries,
|
||||
components: state.components,
|
||||
globals: state.globals,
|
||||
page: state.page,
|
||||
variables: state.variables,
|
||||
client: state.client,
|
||||
server: state.server,
|
||||
constants: state.constants,
|
||||
});
|
||||
useResolveStore.getState().actions.pageSwitched(false);
|
||||
},
|
||||
null,
|
||||
isPageSwitched
|
||||
);
|
||||
|
||||
return useResolveStore.getState().actions.updateStoreState({ storeReady: true });
|
||||
}
|
||||
}, shallow);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ const initialState = {
|
|||
},
|
||||
lastUpdatedRefs: [],
|
||||
referenceMapper: new ReferencesBiMap(),
|
||||
isPageSwitched: false,
|
||||
};
|
||||
|
||||
export const useResolveStore = create(
|
||||
|
|
@ -69,6 +70,10 @@ export const useResolveStore = create(
|
|||
updateStoreState: (state) => {
|
||||
set(() => ({ ...state, storeReady: true }));
|
||||
},
|
||||
resetStore: () => {
|
||||
set(() => initialState);
|
||||
},
|
||||
pageSwitched: (bool) => set(() => ({ isPageSwitched: bool })),
|
||||
updateAppSuggestions: (refState) => {
|
||||
const { suggestionList, hintsMap, resolvedRefs } = createReferencesLookup(refState, false, true);
|
||||
|
||||
|
|
@ -136,13 +141,13 @@ export const useResolveStore = create(
|
|||
},
|
||||
|
||||
removeAppSuggestions: (suggestionsArray) => {
|
||||
if (suggestionsArray.length === 0) return new Promise((resolve) => resolve({ status: '' }));
|
||||
if (suggestionsArray?.length === 0) return new Promise((resolve) => resolve({ status: '' }));
|
||||
|
||||
const lookupHintsMap = new Map([...get().lookupTable.hints]);
|
||||
const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]);
|
||||
const currentSuggestions = get().suggestions.appHints;
|
||||
|
||||
suggestionsArray.forEach((suggestion) => {
|
||||
suggestionsArray?.forEach((suggestion) => {
|
||||
const index = currentSuggestions.findIndex((s) => s.hint === suggestion);
|
||||
|
||||
if (index === -1) return;
|
||||
|
|
|
|||
|
|
@ -505,7 +505,12 @@ export function findAllEntityReferences(node, allRefs) {
|
|||
if (typeof node === 'object') {
|
||||
for (let key in node) {
|
||||
const value = node[key];
|
||||
if (typeof value === 'string' && value.includes('{{') && value.includes('}}')) {
|
||||
if (
|
||||
typeof value === 'string' &&
|
||||
value.includes('{{') &&
|
||||
value.includes('}}') &&
|
||||
(value.startsWith('{{components') || value.startsWith('queries'))
|
||||
) {
|
||||
const referenceExists = value;
|
||||
|
||||
if (referenceExists) {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import { Component } from 'src/entities/component.entity';
|
|||
import { Layout } from 'src/entities/layout.entity';
|
||||
import { EventHandler, Target } from 'src/entities/event_handler.entity';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
interface AppResourceMappings {
|
||||
defaultDataSourceIdMapping: Record<string, string>;
|
||||
dataQueryMapping: Record<string, string>;
|
||||
|
|
|
|||
|
|
@ -25,12 +25,19 @@ import { DataBaseConstraints } from 'src/helpers/db_constraints.constants';
|
|||
import { Page } from 'src/entities/page.entity';
|
||||
import { AppVersionUpdateDto } from '@dto/app-version-update.dto';
|
||||
import { Layout } from 'src/entities/layout.entity';
|
||||
|
||||
import { Component } from 'src/entities/component.entity';
|
||||
import { EventHandler } from 'src/entities/event_handler.entity';
|
||||
import { VersionReleaseDto } from '@dto/version-release.dto';
|
||||
|
||||
import { findAllEntityReferences, isValidUUID, updateEntityReferences } from 'src/helpers/import_export.helpers';
|
||||
import { isEmpty } from 'lodash';
|
||||
const uuid = require('uuid');
|
||||
|
||||
interface AppResourceMappings {
|
||||
dataQueryMapping: Record<string, string>;
|
||||
componentsMapping: Record<string, string>;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class AppsService {
|
||||
constructor(
|
||||
|
|
@ -392,6 +399,11 @@ export class AppsService {
|
|||
const { oldComponentToNewComponentMapping, oldPageToNewPageMapping } =
|
||||
await this.createNewPagesAndComponentsForVersion(manager, appVersion, versionFrom.id, versionFrom.homePageId);
|
||||
|
||||
await this.updateEntityReferencesForNewVersion(manager, {
|
||||
componentsMapping: oldComponentToNewComponentMapping,
|
||||
dataQueryMapping: oldDataQueryToNewMapping,
|
||||
});
|
||||
|
||||
await this.updateEventActionsForNewVersionWithNewMappingIds(
|
||||
manager,
|
||||
appVersion.id,
|
||||
|
|
@ -405,6 +417,64 @@ export class AppsService {
|
|||
}, manager);
|
||||
}
|
||||
|
||||
async updateEntityReferencesForNewVersion(manager: EntityManager, resourceMapping: AppResourceMappings) {
|
||||
const mappings = { ...resourceMapping.componentsMapping, ...resourceMapping.dataQueryMapping };
|
||||
const newComponentIds = Object.values(resourceMapping.componentsMapping);
|
||||
const newQueriesIds = Object.values(resourceMapping.dataQueryMapping);
|
||||
|
||||
if (newComponentIds.length > 0) {
|
||||
const components = await manager
|
||||
.createQueryBuilder(Component, 'components')
|
||||
.where('components.id IN(:...componentIds)', { componentIds: newComponentIds })
|
||||
.select([
|
||||
'components.id',
|
||||
'components.properties',
|
||||
'components.styles',
|
||||
'components.general',
|
||||
'components.validation',
|
||||
'components.generalStyles',
|
||||
'components.displayPreferences',
|
||||
])
|
||||
.getMany();
|
||||
|
||||
const toUpdateComponents = components.filter((component) => {
|
||||
const entityReferencesInComponentDefinitions = findAllEntityReferences(component, []).filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
if (entityReferencesInComponentDefinitions.length > 0) {
|
||||
return updateEntityReferences(component, mappings);
|
||||
}
|
||||
});
|
||||
|
||||
if (!isEmpty(toUpdateComponents)) {
|
||||
await manager.save(toUpdateComponents);
|
||||
}
|
||||
}
|
||||
|
||||
if (newQueriesIds.length > 0) {
|
||||
const dataQueries = await manager
|
||||
.createQueryBuilder(DataQuery, 'dataQueries')
|
||||
.where('dataQueries.id IN(:...dataQueryIds)', { dataQueryIds: newQueriesIds })
|
||||
.select(['dataQueries.id', 'dataQueries.options'])
|
||||
.getMany();
|
||||
|
||||
const toUpdateDataQueries = dataQueries.filter((dataQuery) => {
|
||||
const entityReferencesInQueryOptions = findAllEntityReferences(dataQuery, []).filter(
|
||||
(entity) => entity && isValidUUID(entity)
|
||||
);
|
||||
|
||||
if (entityReferencesInQueryOptions.length > 0) {
|
||||
return updateEntityReferences(dataQuery, mappings);
|
||||
}
|
||||
});
|
||||
|
||||
if (!isEmpty(toUpdateDataQueries)) {
|
||||
await manager.save(toUpdateDataQueries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updateEventActionsForNewVersionWithNewMappingIds(
|
||||
manager: EntityManager,
|
||||
versionId: string,
|
||||
|
|
@ -416,8 +486,10 @@ export class AppsService {
|
|||
where: { appVersionId: versionId },
|
||||
});
|
||||
|
||||
const mappings = { ...oldDataQueryToNewMapping, ...oldComponentToNewComponentMapping } as Record<string, string>;
|
||||
|
||||
for (const event of allEvents) {
|
||||
const eventDefinition = event.event;
|
||||
const eventDefinition = updateEntityReferences(event.event, mappings);
|
||||
|
||||
if (eventDefinition?.actionId === 'run-query') {
|
||||
eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId];
|
||||
|
|
|
|||
Loading…
Reference in a new issue