From e7c7ce795c833e8949a3b566b8140534f7ce9a49 Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Thu, 13 Aug 2026 09:22:14 +0200 Subject: [PATCH 1/7] actions , ref modif Signed-off-by: SOUISSI Maissa (Externe) --- .../network-modification-node-editor.tsx | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index 8bae19fc0c..0e6727ea52 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -22,6 +22,7 @@ import { NetworkModificationMetadata, NetworkModificationsTable, NotificationsUrlKeys, + ReferenceModificationInfos, removeNullFields, setModificationMetadata, snackWithFallback, @@ -179,14 +180,6 @@ const NetworkModificationNodeEditor = () => { [] ); - // TODO : this is temporary, until copy/paste/save is done for the shared modifications in GRD-4785 : - const selectionContainsShared: boolean = useMemo(() => { - return selectedNetworkModifications.some( - (modification: ComposedModificationMetadata) => - modification.type === ModificationType.MODIFICATION_REFERENCE - ); - }, [selectedNetworkModifications]); - const [isDragging, setIsDragging] = useState(false); const [isAssemblyDepthExceeded, setIsAssemblyDepthExceeded] = useState(false); @@ -970,10 +963,21 @@ const NetworkModificationNodeEditor = () => { folderName, folderId, }: IElementCreationDialog) => { - const selectedModificationsUuid = selectedNetworkModifications.map((item) => item.uuid); - setSaveInProgress(true); - createCompositeModifications(name, description, folderId, selectedModificationsUuid) + + Promise.all( + selectedNetworkModifications.map((item) => + item.type === MODIFICATION_TYPES.MODIFICATION_REFERENCE.type + ? fetchNetworkModification(item.uuid as UUID) + .then((res) => res.json()) + .then((detail: ReferenceModificationInfos) => detail.referenceId ?? null) + : Promise.resolve(item.uuid) + ) + ) + .then((uuids) => uuids.filter((uuid): uuid is UUID => uuid !== null)) + .then((selectedModificationsUuid) => + createCompositeModifications(name, description, folderId, selectedModificationsUuid) + ) .then(() => { snackInfo({ headerId: 'infoCreateModificationsMsg', @@ -1325,7 +1329,7 @@ const NetworkModificationNodeEditor = () => { @@ -1341,8 +1345,7 @@ const NetworkModificationNodeEditor = () => { isAnyNodeBuilding || mapDataLoading || !currentNode || - isRootNode || - selectionContainsShared + isRootNode } > @@ -1358,8 +1361,7 @@ const NetworkModificationNodeEditor = () => { selectedNetworkModifications.length === 0 || isAnyNodeBuilding || mapDataLoading || - isRootNode || - selectionContainsShared + isRootNode } > @@ -1381,7 +1383,7 @@ const NetworkModificationNodeEditor = () => { From 911c22960a048ddc3c9c376e8189a53f2b47f31f Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Wed, 19 Aug 2026 11:44:25 +0200 Subject: [PATCH 2/7] remarks Signed-off-by: SOUISSI Maissa (Externe) --- .../network-modification-node-editor.tsx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index 0e6727ea52..2aadbc6810 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -180,6 +180,14 @@ const NetworkModificationNodeEditor = () => { [] ); + // TODO : this is temporary, until merge/delete is done for the shared modification + const selectionContainsShared: boolean = useMemo(() => { + return selectedNetworkModifications.some( + (modification: ComposedModificationMetadata) => + modification.type === ModificationType.MODIFICATION_REFERENCE + ); + }, [selectedNetworkModifications]); + const [isDragging, setIsDragging] = useState(false); const [isAssemblyDepthExceeded, setIsAssemblyDepthExceeded] = useState(false); @@ -970,11 +978,15 @@ const NetworkModificationNodeEditor = () => { item.type === MODIFICATION_TYPES.MODIFICATION_REFERENCE.type ? fetchNetworkModification(item.uuid as UUID) .then((res) => res.json()) - .then((detail: ReferenceModificationInfos) => detail.referenceId ?? null) + .then((detail: ReferenceModificationInfos) => { + if (detail.referenceId == null) { + throw new Error(`Missing referenceId for modification reference ${item.uuid}`); + } + return detail.referenceId; + }) : Promise.resolve(item.uuid) ) ) - .then((uuids) => uuids.filter((uuid): uuid is UUID => uuid !== null)) .then((selectedModificationsUuid) => createCompositeModifications(name, description, folderId, selectedModificationsUuid) ) @@ -1255,8 +1267,20 @@ const NetworkModificationNodeEditor = () => { ); const disabledCompositeCreation: boolean = useMemo(() => { - return selectedNetworkModifications?.length === 0 || saveInProgress || isRootNode || isAssemblyDepthExceeded; - }, [selectedNetworkModifications, saveInProgress, isRootNode, isAssemblyDepthExceeded]); + return ( + selectedNetworkModifications?.length === 0 || + saveInProgress || + isRootNode || + isAssemblyDepthExceeded || + selectionContainsShared + ); + }, [ + selectedNetworkModifications?.length, + saveInProgress, + isRootNode, + isAssemblyDepthExceeded, + selectionContainsShared, + ]); const disabledCompositeExport: boolean = useMemo(() => { return ( From fe29e1d266f57f5cb70ffebbe5716ffbc488d4d0 Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Fri, 21 Aug 2026 03:47:02 +0200 Subject: [PATCH 3/7] move copy a reference Signed-off-by: SOUISSI Maissa (Externe) --- .../network-modification-menu.type.ts | 6 ++++ .../network-modification-node-editor.tsx | 33 +++++++++++-------- .../use-copied-network-modifications.ts | 4 +-- src/redux/reducer.ts | 2 +- src/services/study/index.ts | 5 +-- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/components/graph/menus/network-modifications/network-modification-menu.type.ts b/src/components/graph/menus/network-modifications/network-modification-menu.type.ts index d86cac5e2c..c66c1035ce 100644 --- a/src/components/graph/menus/network-modifications/network-modification-menu.type.ts +++ b/src/components/graph/menus/network-modifications/network-modification-menu.type.ts @@ -9,6 +9,7 @@ import type { UUID } from 'node:crypto'; import { CurrentTreeNode } from '../../tree-node.type'; import { FetchStatus } from '../../../../services/utils.type'; import { JSX } from 'react'; +import { ModificationContainer } from '@gridsuite/commons-ui'; export interface RootNetworkMetadata { rootNetworkUuid: UUID; @@ -49,6 +50,11 @@ export interface NetworkModificationCopyInfos { originNodeUuid?: UUID; } +export interface ModificationMoveOrCopyInfos { + modificationUuid: UUID; + source?: ModificationContainer; +} + export interface MenuDefinitionSubItem { id: string; label: string; diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index 2aadbc6810..6a10618e11 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -101,6 +101,7 @@ import { MenuDefinitionSubItem, MenuDefinitionWithoutSubItem, MenuSection, + ModificationMoveOrCopyInfos, NetworkModificationCopyInfos, NetworkModificationCopyType, NetworkModificationData, @@ -179,7 +180,7 @@ const NetworkModificationNodeEditor = () => { const [selectedNetworkModifications, setSelectedNetworkModifications] = useState( [] ); - + console.log('======== ', selectedNetworkModifications); // TODO : this is temporary, until merge/delete is done for the shared modification const selectionContainsShared: boolean = useMemo(() => { return selectedNetworkModifications.some( @@ -230,7 +231,7 @@ const NetworkModificationNodeEditor = () => { // a modification on a public study which is in the clipboard. // We don't have precision on notifications to do this for now. const handleValidatedDialog = () => { - if (editData?.uuid && networkModificationsToCopy.includes(editData?.uuid)) { + if (editData?.uuid && networkModificationsToCopy.some((m) => m.uuid === editData?.uuid)) { cleanClipboard(); } }; @@ -930,7 +931,7 @@ const NetworkModificationNodeEditor = () => { //if one of the deleted element was in the clipboard we invalidate the clipboard if ( networkModificationsToCopy.some((aCopiedModification) => - selectedModificationsUuid.includes(aCopiedModification) + selectedModificationsUuid.includes(aCopiedModification.uuid) ) ) { cleanClipboard(); @@ -1039,39 +1040,43 @@ const NetworkModificationNodeEditor = () => { }); }; - const selectedModificationsIds = useMemo( - () => selectedNetworkModifications.map((m) => m.uuid), - [selectedNetworkModifications] - ); - const doCutModifications = useCallback(() => { cutNetworkModifications({ - networkModificationUuids: selectedModificationsIds, + networkModifications: selectedNetworkModifications, copyInfos: { copyType: NetworkModificationCopyType.MOVE, originStudyUuid: studyUuid ?? undefined, originNodeUuid: currentNode?.id, }, }); - }, [cutNetworkModifications, currentNode?.id, selectedModificationsIds, studyUuid]); + }, [cutNetworkModifications, currentNode?.id, selectedNetworkModifications, studyUuid]); const doCopyModifications = useCallback(() => { copyNetworkModifications({ - networkModificationUuids: selectedModificationsIds, + networkModifications: selectedNetworkModifications, copyInfos: { copyType: NetworkModificationCopyType.COPY, originStudyUuid: studyUuid ?? undefined, originNodeUuid: currentNode?.id, }, }); - }, [copyNetworkModifications, currentNode?.id, selectedModificationsIds, studyUuid]); + }, [copyNetworkModifications, currentNode?.id, selectedNetworkModifications, studyUuid]); const doPasteModifications = useCallback(() => { if (!copyInfos || !studyUuid || !currentNode?.id) { return; } + // no source hint: study-server now looks up each modification's real container itself + // (network-modification-server owns that data), instead of this having to guess it from + // whatever the table's selection happens to expose + const modificationsToMoveOrCopy: ModificationMoveOrCopyInfos[] = networkModificationsToCopy.map( + (modification) => ({ + modificationUuid: modification.uuid, + }) + ); + if (copyInfos.copyType === NetworkModificationCopyType.MOVE) { - copyOrMoveModifications(studyUuid, currentNode.id, networkModificationsToCopy, copyInfos) + copyOrMoveModifications(studyUuid, currentNode.id, modificationsToMoveOrCopy, copyInfos) .then(() => { cleanClipboard(false); }) @@ -1081,7 +1086,7 @@ const NetworkModificationNodeEditor = () => { }); }); } else { - copyOrMoveModifications(studyUuid, currentNode.id, networkModificationsToCopy, copyInfos).catch((error) => { + copyOrMoveModifications(studyUuid, currentNode.id, modificationsToMoveOrCopy, copyInfos).catch((error) => { snackWithFallback(snackError, error, { headerId: 'errDuplicateModificationMsg', }); diff --git a/src/hooks/copy-paste/use-copied-network-modifications.ts b/src/hooks/copy-paste/use-copied-network-modifications.ts index 50b465eb9d..634c1fff51 100644 --- a/src/hooks/copy-paste/use-copied-network-modifications.ts +++ b/src/hooks/copy-paste/use-copied-network-modifications.ts @@ -14,7 +14,7 @@ import { setCopiedNetworkModifications } from 'redux/actions'; const networkModificationsCopyChannel = new BroadcastChannel('NetworkModificationsCopyBroadcastChannel'); const emptyCopiedNetworkModificationsSelection: CopiedNetworkModifications = { - networkModificationUuids: [], + networkModifications: [], copyInfos: null, }; @@ -23,7 +23,7 @@ export const useCopiedNetworkModifications = () => { const { snackInfo } = useSnackMessage(); const networkModificationsToCopy = useSelector( - (state: AppState) => state.copiedNetworkModifications.networkModificationUuids + (state: AppState) => state.copiedNetworkModifications.networkModifications ); const copyInfos = useSelector((state: AppState) => state.copiedNetworkModifications.copyInfos); const isInitiatingCopyTab = useRef(false); diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index 8d0628dcb8..70cc3a1b96 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -485,7 +485,7 @@ const initialState: AppState = { allChildren: null, }, copiedNetworkModifications: { - networkModificationUuids: [], + networkModifications: [], copyInfos: null, }, tables: initialTablesState, diff --git a/src/services/study/index.ts b/src/services/study/index.ts index 458f0a5bce..656d1eab9b 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -21,6 +21,7 @@ import { } from '@gridsuite/commons-ui'; import { CompositeModificationAction, + ModificationMoveOrCopyInfos, NetworkModificationCopyInfos, } from 'components/graph/menus/network-modifications/network-modification-menu.type'; import type { Svg } from 'components/grid-layout/cards/diagrams/diagram.type'; @@ -256,7 +257,7 @@ export function executeCompositeModificationAction( export function copyOrMoveModifications( studyUuid: UUID, targetNodeId: UUID, - modificationToCutUuidList: UUID[], + modificationsToCopyOrMove: ModificationMoveOrCopyInfos[], copyInfos: NetworkModificationCopyInfos ) { console.info(copyInfos.copyType + ' modifications'); @@ -279,7 +280,7 @@ export function copyOrMoveModifications( Accept: 'application/json', 'Content-Type': 'application/json', }, - body: JSON.stringify(modificationToCutUuidList), + body: JSON.stringify(modificationsToCopyOrMove), }); } From b26084fc9b19103505cc167ee99be1d351fe0383 Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Fri, 21 Aug 2026 03:47:41 +0200 Subject: [PATCH 4/7] move copy a reference Signed-off-by: SOUISSI Maissa (Externe) --- src/redux/reducer.type.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/redux/reducer.type.ts b/src/redux/reducer.type.ts index aee9ec9de1..b0c3d5e098 100644 --- a/src/redux/reducer.type.ts +++ b/src/redux/reducer.type.ts @@ -9,6 +9,7 @@ import type { AuthenticationRouterErrorState, BaseVoltage, CommonStoreState, + ComposedModificationMetadata, ComputingType, GsLang, GsLangUser, @@ -184,7 +185,9 @@ export type NodeSelectionForCopy = { }; export type CopiedNetworkModifications = { - networkModificationUuids: UUID[]; + // the raw selection snapshot at copy/cut time; doPasteModifications resolves it into + // ModificationMoveOrCopyInfos (per-item source container) right before sending the request + networkModifications: ComposedModificationMetadata[]; copyInfos: NetworkModificationCopyInfos | null; }; From e2e1ea4c0cb21eb2bf4e157537748d5d20bc3fb2 Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Wed, 26 Aug 2026 23:27:27 +0200 Subject: [PATCH 5/7] comments clean Signed-off-by: SOUISSI Maissa (Externe) --- .../network-modifications/network-modification-node-editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index fa5560b61d..bd3374cfdd 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -170,7 +170,7 @@ const NetworkModificationNodeEditor = () => { const [selectedNetworkModifications, setSelectedNetworkModifications] = useState( [] ); - console.log('======== ', selectedNetworkModifications); + // TODO : this is temporary, until merge/delete is done for the shared modification const selectionContainsShared: boolean = useMemo(() => { return selectedNetworkModifications.some( From 3b96b8c154474ef9c26dec3146ceda6752e5f74b Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Thu, 27 Aug 2026 10:51:52 +0200 Subject: [PATCH 6/7] reception shared element notification Signed-off-by: SOUISSI Maissa (Externe) --- .../network-modification-node-editor.tsx | 15 ++++++++++++++ .../use-root-network-search-notifications.ts | 4 +++- src/types/notification-types.ts | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index bd3374cfdd..fb9559c620 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -116,6 +116,7 @@ import { isModificationsDeleteFinishedNotification, isModificationsUpdateFinishedNotification, isNodeDeletedNotification, + isSharedElementUpdateNotification, parseEventData, } from 'types/notification-types'; import { LccModificationDialog } from '../../../dialogs/network-modifications/hvdc-line/lcc/modification/lcc-modification-dialog'; @@ -801,6 +802,20 @@ const NetworkModificationNodeEditor = () => { } dofetchNetworkModifications(); } + + // a shared (referenced) composite modification pointed at by this node was edited + // elsewhere. Re-fetching the group hands NetworkModificationsTable a fresh + // `modifications` identity, which makes it force-refresh the resolved content of every + // expanded composite / reference row (fetchSubModificationsForExpandedRows(..., force)); + // a collapsed reference reloads its content the next time it is expanded. + if (isSharedElementUpdateNotification(eventData)) { + console.log("EVENT ??????????") + if (currentNodeIdRef.current !== eventData.headers.parentNode) { + return; + } + dofetchNetworkModifications(); + dofetchExcludedNetworkModifications(); + } }, [dofetchNetworkModifications, cleanClipboard, dofetchExcludedNetworkModifications] ); diff --git a/src/components/graph/menus/root-network/use-root-network-search-notifications.ts b/src/components/graph/menus/root-network/use-root-network-search-notifications.ts index 0865e1629e..2043169239 100644 --- a/src/components/graph/menus/root-network/use-root-network-search-notifications.ts +++ b/src/components/graph/menus/root-network/use-root-network-search-notifications.ts @@ -18,6 +18,7 @@ import { isNodeEditedNotification, isNodeSubTreeCreatedNotification, isRootNetworksUpdatedNotification, + isSharedElementUpdateNotification, } from 'types/notification-types'; type UseRootNetworkNotificationsProps = { @@ -39,7 +40,8 @@ export const useRootNetworkSearchNotifications = ({ const rootNetworksStatus = isRootNetworksUpdatedNotification(eventData); const networkModificationsStatus = isModificationsDeleteFinishedNotification(eventData) || - isModificationsUpdateFinishedNotification(eventData); + isModificationsUpdateFinishedNotification(eventData) || + isSharedElementUpdateNotification(eventData); const nodeDeleted = isNodeDeletedNotification(eventData); const nodeCreated = isNodeCreatedNotification(eventData); const nodeEdited = isNodeEditedNotification(eventData); diff --git a/src/types/notification-types.ts b/src/types/notification-types.ts index 9daee4d293..042b3dcd18 100644 --- a/src/types/notification-types.ts +++ b/src/types/notification-types.ts @@ -41,6 +41,7 @@ export enum NotificationType { // Modifications MODIFICATIONS_UPDATE_FINISHED = 'UPDATE_FINISHED', MODIFICATIONS_DELETE_FINISHED = 'DELETE_FINISHED', + SHARED_ELEMENT_UPDATE = 'sharedElementUpdate', // Events EVENT_CRUD_FINISHED = 'EVENT_CRUD_FINISHED', @@ -279,6 +280,16 @@ interface ModificationsDeleteFinishedEventDataHeaders extends CommonStudyEventDa nodes: UUID[]; } +// Emitted by study-server (ConsumerService.consumeSharedElementUpdate) once per invalidated node +// when a shared (referenced) composite modification pointed at by that node was edited elsewhere. +// `parentNode` is the impacted node; `networkModificationUuids` are the reference modifications +// (across all impacted nodes) that point at the edited shared element. +interface SharedElementUpdateEventDataHeaders extends CommonStudyEventDataHeaders { + updateType: NotificationType.SHARED_ELEMENT_UPDATE; + parentNode: UUID; + networkModificationUuids?: UUID[]; +} + interface EventCrudFinishedEventDataHeaders extends CommonStudyEventDataHeaders { updateType: NotificationType.EVENT_CRUD_FINISHED; parentNode: UUID; @@ -484,6 +495,11 @@ export interface ModificationsUpdateFinishedEventData extends CommonStudyEventDa payload: undefined; } +export interface SharedElementUpdateEventData extends CommonStudyEventData { + headers: SharedElementUpdateEventDataHeaders; + payload: undefined; +} + export interface ModificationsDeleteFinishedEventData extends CommonStudyEventData { headers: ModificationsDeleteFinishedEventDataHeaders; payload: undefined; @@ -674,6 +690,10 @@ export function isModificationsDeleteFinishedNotification( return notif.headers?.updateType === NotificationType.MODIFICATIONS_DELETE_FINISHED; } +export function isSharedElementUpdateNotification(notif: CommonStudyEventData): notif is SharedElementUpdateEventData { + return notif.headers?.updateType === NotificationType.SHARED_ELEMENT_UPDATE; +} + export function isIndexationStatusNotification(notif: CommonStudyEventData): notif is IndexationStatusEventData { return notif.headers?.updateType === NotificationType.INDEXATION_STATUS; } From 1eba0f9f14af36584812cde47f94f040571cb479 Mon Sep 17 00:00:00 2001 From: "SOUISSI Maissa (Externe)" Date: Tue, 1 Sep 2026 11:30:11 +0200 Subject: [PATCH 7/7] clean Signed-off-by: SOUISSI Maissa (Externe) --- .../network-modification-node-editor.tsx | 1 - src/types/notification-types.ts | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx index a03ffb0983..4396d90b87 100644 --- a/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx +++ b/src/components/graph/menus/network-modifications/network-modification-node-editor.tsx @@ -809,7 +809,6 @@ const NetworkModificationNodeEditor = () => { // expanded composite / reference row (fetchSubModificationsForExpandedRows(..., force)); // a collapsed reference reloads its content the next time it is expanded. if (isSharedElementUpdateNotification(eventData)) { - console.log("EVENT ??????????") if (currentNodeIdRef.current !== eventData.headers.parentNode) { return; } diff --git a/src/types/notification-types.ts b/src/types/notification-types.ts index 042b3dcd18..a50c4e3a7f 100644 --- a/src/types/notification-types.ts +++ b/src/types/notification-types.ts @@ -280,10 +280,6 @@ interface ModificationsDeleteFinishedEventDataHeaders extends CommonStudyEventDa nodes: UUID[]; } -// Emitted by study-server (ConsumerService.consumeSharedElementUpdate) once per invalidated node -// when a shared (referenced) composite modification pointed at by that node was edited elsewhere. -// `parentNode` is the impacted node; `networkModificationUuids` are the reference modifications -// (across all impacted nodes) that point at the edited shared element. interface SharedElementUpdateEventDataHeaders extends CommonStudyEventDataHeaders { updateType: NotificationType.SHARED_ELEMENT_UPDATE; parentNode: UUID;