From 413adc1ba50d31317d08809193dafb4c1ba05cd8 Mon Sep 17 00:00:00 2001 From: markus-moser Date: Fri, 24 Jan 2025 11:07:28 +0100 Subject: [PATCH 1/3] Add first version of data object data save process --- .../data-object/data-object-draft-slice.tsx | 14 ++- .../draft/hooks/use-modified-object-data.ts | 90 +++++++++++++++++++ .../data-object/editor/toolbar/toolbar.tsx | 4 + .../tabs/edit/components/root-component.tsx | 47 ++++++---- .../hooks/use-data-object-draft.ts | 18 +++- .../structured-table/components/grid/grid.tsx | 2 - 6 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 assets/js/src/core/modules/data-object/draft/hooks/use-modified-object-data.ts diff --git a/assets/js/src/core/modules/data-object/data-object-draft-slice.tsx b/assets/js/src/core/modules/data-object/data-object-draft-slice.tsx index fe8e7f14e..db6627658 100644 --- a/assets/js/src/core/modules/data-object/data-object-draft-slice.tsx +++ b/assets/js/src/core/modules/data-object/data-object-draft-slice.tsx @@ -26,8 +26,12 @@ import { } from '@Pimcore/modules/element/draft/hooks/use-tabs' import { type SchedulesDraft, useSchedulesReducers } from '@Pimcore/modules/element/draft/hooks/use-schedules' import { type DataObject } from '@Pimcore/modules/data-object/data-object-api-slice-enhanced' +import { + type ModifiedObjectDataDraft, + useModifiedObjectDataReducers +} from '@Pimcore/modules/data-object/draft/hooks/use-modified-object-data' -export interface DataObjectDraft extends DataObject, PropertiesDraft, SchedulesDraft, TrackableChangesDraft, TabsDraft { +export interface DataObjectDraft extends DataObject, PropertiesDraft, SchedulesDraft, TrackableChangesDraft, TabsDraft, ModifiedObjectDataDraft { } export const dataObjectsAdapter: EntityAdapter = createEntityAdapter({}) @@ -40,6 +44,7 @@ export const slice = createSlice({ schedule: [], changes: {}, modifiedCells: {}, + modifiedObjectData: {}, ...initialTabsStateValue }), reducers: { @@ -57,7 +62,8 @@ export const slice = createSlice({ ...useTrackableChangesReducers(dataObjectsAdapter), ...usePropertiesReducers(dataObjectsAdapter), ...useSchedulesReducers(dataObjectsAdapter), - ...useTabsReducers(dataObjectsAdapter) + ...useTabsReducers(dataObjectsAdapter), + ...useModifiedObjectDataReducers(dataObjectsAdapter) } }) @@ -81,7 +87,9 @@ export const { setSchedules: setSchedulesForDataObject, updateSchedule: updateScheduleForDataObject, resetSchedulesChanges: resetSchedulesChangesForDataObject, - setActiveTab: setActiveTabForDataObject + setActiveTab: setActiveTabForDataObject, + + trackModifiedObjectData } = slice.actions export const { selectById: selectDataObjectById } = dataObjectsAdapter.getSelectors((state: RootState) => state['data-object-draft']) diff --git a/assets/js/src/core/modules/data-object/draft/hooks/use-modified-object-data.ts b/assets/js/src/core/modules/data-object/draft/hooks/use-modified-object-data.ts new file mode 100644 index 000000000..de520d8c8 --- /dev/null +++ b/assets/js/src/core/modules/data-object/draft/hooks/use-modified-object-data.ts @@ -0,0 +1,90 @@ +/** +* Pimcore +* +* This source file is available under two different licenses: +* - Pimcore Open Core License (POCL) +* - Pimcore Commercial License (PCL) +* Full copyright and license information is available in +* LICENSE.md which is distributed with this source code. +* +* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) +* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL +*/ + +import type { ActionCreatorWithPayload, PayloadAction } from '@reduxjs/toolkit' +import type { EntityAdapter, EntityState } from '@reduxjs/toolkit/src/entities/models' + +import { useAppDispatch } from '@Pimcore/app/store' + +import { type TrackableChangesDraft } from '@Pimcore/modules/element/draft/hooks/use-trackable-changes' +import _ from 'lodash' + +export interface ModifiedObjectDataAction { + id: number + values: any +} + +export interface ModifiedObjectDataDraft extends TrackableChangesDraft { + modifiedObjectData: Record +} + +interface UseModifiedObjectDataReturn { + trackModifiedObjectData: (state: EntityState, action: PayloadAction) => void +} + +export const useModifiedObjectDataReducers = (entityAdapter: EntityAdapter): UseModifiedObjectDataReturn => { + const trackModifiedObjectData = (state: EntityState, action: PayloadAction): void => { + modifyDraft(state, action.payload.id, (draft: ModifiedObjectDataDraft): ModifiedObjectDataDraft => { + draft.modifiedObjectData = _.merge({}, draft.modifiedObjectData, action.payload.values) + + markedAsModified(draft) + return draft + }) + } + + const modifyDraft = (state: EntityState, id: number, modification: (draft: ModifiedObjectDataDraft) => ModifiedObjectDataDraft): void => { + const draft = entityAdapter.getSelectors().selectById(state, id) + if (draft === undefined) { + console.error(`Object draft with id ${id} not found`) + return + } + + state.entities[id] = modification({ ...draft }) + + console.log('my modified draft', draft?.modifiedObjectData) + } + + const markedAsModified = (draft: ModifiedObjectDataDraft): void => { + draft.modified = true + + draft.changes = { + ...draft.changes, + objectData: true + } + } + + return { + trackModifiedObjectData + } +} + +export interface UseModifiedObjectDataDraftReturn { + modifiedObjectData: Record + trackModifiedObjectData: (values: any) => void +} + +export const useModifiedObjectDataDraft = ( + id: number, + draft: ModifiedObjectDataDraft, + trackModifiedObjectDataAction: ActionCreatorWithPayload +): UseModifiedObjectDataDraftReturn => { + const dispatch = useAppDispatch() + + return { + modifiedObjectData: draft?.modifiedObjectData ?? {}, + + trackModifiedObjectData: (values: any): void => { + dispatch(trackModifiedObjectDataAction({ id, values })) + } + } +} diff --git a/assets/js/src/core/modules/data-object/editor/toolbar/toolbar.tsx b/assets/js/src/core/modules/data-object/editor/toolbar/toolbar.tsx index ae17f9a5b..ffd38062c 100644 --- a/assets/js/src/core/modules/data-object/editor/toolbar/toolbar.tsx +++ b/assets/js/src/core/modules/data-object/editor/toolbar/toolbar.tsx @@ -114,6 +114,10 @@ export const Toolbar = (): React.JSX.Element => { update.properties = propertyUpdate?.filter((property) => !property.inherited) } + if (dataObject.changes.objectData) { + update.editableData = dataObject.modifiedObjectData + } + const saveDataObjectPromise = saveDataObject({ id, body: { diff --git a/assets/js/src/core/modules/data-object/editor/types/object/tab-manager/tabs/edit/components/root-component.tsx b/assets/js/src/core/modules/data-object/editor/types/object/tab-manager/tabs/edit/components/root-component.tsx index c594802d7..3bf0a5efd 100644 --- a/assets/js/src/core/modules/data-object/editor/types/object/tab-manager/tabs/edit/components/root-component.tsx +++ b/assets/js/src/core/modules/data-object/editor/types/object/tab-manager/tabs/edit/components/root-component.tsx @@ -11,11 +11,14 @@ * @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL */ -import React from 'react' +import React, { useCallback, useRef } from 'react' import { ObjectComponent } from './object-component' import { Form } from '@Pimcore/components/form/form' import { Button, ConfigProvider } from 'antd' import { type DataObjectGetLayoutByIdApiResponse } from '@Pimcore/modules/data-object/data-object-api-slice.gen' +import { useDataObjectDraft } from '@Pimcore/modules/data-object/hooks/use-data-object-draft' +import { useElementContext } from '@Pimcore/modules/element/hooks/use-element-context' +import { debounce } from 'lodash' interface RootComponentProps { layout: DataObjectGetLayoutByIdApiResponse @@ -24,24 +27,42 @@ interface RootComponentProps { } export const RootComponent = ({ layout, data, className }: RootComponentProps): React.JSX.Element => { + const { id } = useElementContext() + const { trackModifiedObjectData } = useDataObjectDraft(id) + const modifiedDataObjectAttributesRef = useRef({}) + + const debouncedTrackModifiedDataObjectAttribute = useCallback( + debounce((currentAttributes: Record) => { + commitToDraft(currentAttributes) + }, 300), + [trackModifiedObjectData] + ) + + const handleValuesChange = (changedValues: Record): void => { + modifiedDataObjectAttributesRef.current = { ...modifiedDataObjectAttributesRef.current, ...changedValues } + debouncedTrackModifiedDataObjectAttribute({ ...modifiedDataObjectAttributesRef.current }) + } + + const handleSubmit = (): void => { + commitToDraft(modifiedDataObjectAttributesRef.current) + } + + const commitToDraft = (changedValues: Record): void => { + trackModifiedObjectData({ ...changedValues }) + modifiedDataObjectAttributesRef.current = {} + } + return ( - +
-