diff --git a/frontend/src/Editor/Editor.jsx b/frontend/src/Editor/Editor.jsx index 7b41e556d1..fc20c1caa1 100644 --- a/frontend/src/Editor/Editor.jsx +++ b/frontend/src/Editor/Editor.jsx @@ -82,7 +82,12 @@ import { HotkeysProvider } from 'react-hotkeys-hook'; import { useResolveStore } from '@/_stores/resolverStore'; import { dfs } from '@/_stores/handleReferenceTransactions'; import { decimalToHex, EditorConstants } from './editorConstants'; -import { handleLowPriorityWork, updateCanvasBackground, clearAllQueuedTasks } from '@/_helpers/editorHelpers'; +import { + handleLowPriorityWork, + updateCanvasBackground, + clearAllQueuedTasks, + checkAndExtractEntityId, +} from '@/_helpers/editorHelpers'; import { TJLoader } from '@/_ui/TJLoader/TJLoader'; import cx from 'classnames'; import { resolveReferences } from './CodeEditor/utils'; @@ -286,7 +291,7 @@ const EditorComponent = (props) => { if (appDiffOptions?.skipAutoSave === true || appDiffOptions?.entityReferenceUpdated === true) return; - handleLowPriorityWork(() => autoSave(), 100); + autoSave(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]); @@ -1038,26 +1043,24 @@ const EditorComponent = (props) => { } //Todo: Move this to a separate function or as a middleware of the api to createing a component - 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 }); - } - }); + 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' && @@ -1080,13 +1083,24 @@ const EditorComponent = (props) => { isUpdatingEditorStateInProcess: false, }); }) - .catch((err) => { + .catch((e) => { + const entityNotSaved = + e?.data?.statusCode === 500 && e?.error + ? checkAndExtractEntityId(e.error) + : { entityId: null, message: 'App could not be saved.' }; + + let errMessage = e?.data?.message || 'App could not be saved.'; + if (entityNotSaved.entityId) { + const componentName = + appDefinition.pages[currentPageId].components[entityNotSaved.entityId]?.component?.name; + errMessage = `The component "${componentName}" could not be saved, so the last action is also not saved.`; + } + updateEditorState({ saveError: true, isUpdatingEditorStateInProcess: false, }); - // toast.error('App could not save.'); - toast.error(err?.error ?? 'App could not save.'); + toast.error(errMessage); }) .finally(() => { if (appDiffOptions?.cloningComponent) { diff --git a/frontend/src/_helpers/editorHelpers.js b/frontend/src/_helpers/editorHelpers.js index 3d6b744c7f..2869a072ac 100644 --- a/frontend/src/_helpers/editorHelpers.js +++ b/frontend/src/_helpers/editorHelpers.js @@ -336,3 +336,18 @@ export const updateCanvasBackground = ({ canvasBackgroundColor, backgroundFxQuer } } }; + +export function checkAndExtractEntityId(errorString) { + const regex = /"([a-f0-9-]+)"/; + const match = errorString.match(regex); + if (match && match[1]) { + return { + entityId: match[1], + message: 'The last component is not saved, so the last action is also not saved.', + }; + } + return { + entityId: null, + message: 'No entity ID found in the error message.', + }; +} diff --git a/frontend/src/_stores/appDataStore.js b/frontend/src/_stores/appDataStore.js index 99ff1e3de0..d87babcfd9 100644 --- a/frontend/src/_stores/appDataStore.js +++ b/frontend/src/_stores/appDataStore.js @@ -7,6 +7,7 @@ import { useDataQueriesStore } from './dataQueriesStore'; import _ from 'lodash'; import { dfs, handleReferenceTransactions } from './handleReferenceTransactions'; import { isValidUUID } from '@/_helpers/utils'; +import toast from 'react-hot-toast'; const initialState = { editingVersion: null, @@ -137,13 +138,22 @@ export const useAppDataStore = create( const versionId = get().currentVersionId; const updatedEvents = get().events; - const response = await appVersionService.createAppVersionEventHandler(appId, versionId, event); - get().actions.setIsSaving(false); - set({ eventsCreatedLoader: false }); + appVersionService + .createAppVersionEventHandler(appId, versionId, event) + .then((response) => { + get().actions.setIsSaving(false); + set({ eventsCreatedLoader: false }); - updatedEvents.push(response); + updatedEvents.push(response); - set(() => ({ events: updatedEvents })); + set(() => ({ events: updatedEvents })); + }) + .catch((err) => { + get().actions.setIsSaving(false); + set({ eventsCreatedLoader: false }); + + toast.error(err?.error || 'An error occurred while creating the event handler'); + }); }, deleteAppVersionEventHandler: async (eventId) => { diff --git a/server/src/services/components.service.ts b/server/src/services/components.service.ts index f4a9ad9072..bee2b1a8bc 100644 --- a/server/src/services/components.service.ts +++ b/server/src/services/components.service.ts @@ -72,9 +72,9 @@ export class ComponentsService { for (const componentId in componentDiff) { const { component } = componentDiff[componentId]; - const componentData: Component = await manager.findOne(Component, componentId); + const doesComponentExist = await manager.findOneOrFail(Component, componentId); - if (!componentData) { + if (doesComponentExist[1] === 0) { return { error: { message: `Component with id ${componentId} does not exist`, @@ -82,6 +82,8 @@ export class ComponentsService { }; } + const componentData: Component = await manager.findOne(Component, componentId); + const isComponentDefinitionChanged = component.definition ? true : false; if (isComponentDefinitionChanged) { @@ -151,9 +153,9 @@ export class ComponentsService { ) { return dbTransactionForAppVersionAssociationsUpdate(async (manager: EntityManager) => { for (const componentId in componenstLayoutDiff) { - const doesComponentExist = await manager.findAndCount(Component, { id: componentId }); + const doesComponentExist = await manager.findOneOrFail(Component, componentId); - if (!doesComponentExist[1]) { + if (doesComponentExist[1] === 0) { return { error: { message: `Component with id ${componentId} does not exist`, diff --git a/server/src/services/events_handler.service.ts b/server/src/services/events_handler.service.ts index be4216fbeb..94c7c36fab 100644 --- a/server/src/services/events_handler.service.ts +++ b/server/src/services/events_handler.service.ts @@ -51,6 +51,40 @@ export class EventsService { } return await dbTransactionForAppVersionAssociationsUpdate(async (manager: EntityManager) => { + if ( + eventHandler.eventType === 'component' || + eventHandler.eventType === 'table_column' || + eventHandler.eventType === 'table_action' + ) { + const componentExists = await manager.findOne('Component', { + id: eventHandler.attachedTo, + }); + + if (!componentExists) { + throw new BadRequestException('Component does not exist'); + } + } + + if (eventHandler.eventType === 'data_query') { + const dataQueryExists = await manager.findOne('DataQuery', { + id: eventHandler.attachedTo, + }); + + if (!dataQueryExists) { + throw new BadRequestException('Data Query does not exist'); + } + } + + if (eventHandler.eventType === 'page') { + const pageExists = await manager.findOne('Page', { + id: eventHandler.attachedTo, + }); + + if (!pageExists) { + throw new BadRequestException('Page does not exist'); + } + } + const newEvent = new EventHandler(); newEvent.name = eventHandler.event.eventId; newEvent.sourceId = eventHandler.attachedTo;