neos-ui
neos-ui copied to clipboard
Bug: Paste of multiple content nodes results in wrong order
Description
If you copy multiple content nodes from one document and paste them in another document the order of the copied content nodes can get somewhat mixed up.
The actual paste is done by /neos/ui-services/change
, but I think the request payload provided has a wrong order. Thus I think it's an issue of the JS part of the neos ui - see below for request details.
Steps to Reproduce
- Open the backend UI and copy content nodes from a document
- Paste them in another document
Expected behavior
The pasted order is preserved.
Actual behavior
The order depends on where you paste it in the target document:
- Paste
before
some other content node - This works - Paste
after
some content node - The order is reversed - Click the
main
content collection of the target document and just click the paste button - The order is mixed in between content elements
Captured requests
I'm not quite sure what exactly is going on in case of the Mixed order
, but for the CopyAfter
operation, the set of nodes to paste should be reversed in the request payload.
If you look at the working request, that is the CopyBefore
operation, the reason why the order is correct is, that the copied nodes are copied before the siblingDomAddress
in the order given. Thus the same order appears.
In case of the CopyAfter
, let's assume we want to copy nodes n1
,n2
,n3
in that order after node c
. After the first operation we have the order c
,n1
. Looks good. Then n2
is copied after c
, thus the order c
, n2
, n1
appears. The same with n3
and we get the final reversed order c
, n3
, n2
, n1
.
At least, that's what I think happens.
Working request
{
"changes": [
{
"payload": {
"baseNodeType": "",
"parentDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"fusionPath": "root<Neos.Fusion:Case>/documentType<Neos.Fusion:Matcher>/element<Webco.Fou001:Document.Article>/body<Neos.Fusion:Array>/content<Webco.Fou001:Component.Template.Article>/main<Neos.Neos:PrimaryContent>/default<Neos.Fusion:Matcher>/renderer"
},
"siblingDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main/node-i5r8tys0jngkm@user-gj;language=en,all"
}
},
"subject": "/sites/hub/node-qq1qu5bhs68k5/node-np2yc2v4ue6jf/node-ki3oy5drp9bv4/node-bi4u02u3lhfm4/main/node-8smjfu7zyxjpc@user-gj;language=en,all",
"type": "Neos.Neos.Ui:CopyBefore"
},
{
"payload": {
"baseNodeType": "",
"parentDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"fusionPath": "root<Neos.Fusion:Case>/documentType<Neos.Fusion:Matcher>/element<Webco.Fou001:Document.Article>/body<Neos.Fusion:Array>/content<Webco.Fou001:Component.Template.Article>/main<Neos.Neos:PrimaryContent>/default<Neos.Fusion:Matcher>/renderer"
},
"siblingDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main/node-i5r8tys0jngkm@user-gj;language=en,all"
}
},
"subject": "/sites/hub/node-qq1qu5bhs68k5/node-np2yc2v4ue6jf/node-ki3oy5drp9bv4/node-bi4u02u3lhfm4/main/node-a5991ukjekq57@user-gj;language=en,all",
"type": "Neos.Neos.Ui:CopyBefore"
}
]
}
Reverse order
{
"changes": [
{
"payload": {
"baseNodeType": "",
"parentDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"fusionPath": "root<Neos.Fusion:Case>/documentType<Neos.Fusion:Matcher>/element<Webco.Fou001:Document.Article>/body<Neos.Fusion:Array>/content<Webco.Fou001:Component.Template.Article>/main<Neos.Neos:PrimaryContent>/default<Neos.Fusion:Matcher>/renderer"
},
"siblingDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main/node-i888xtewx12b1@user-gj;language=en,all"
}
},
"subject": "/sites/hub/node-qq1qu5bhs68k5/node-np2yc2v4ue6jf/node-ki3oy5drp9bv4/node-bi4u02u3lhfm4/main/node-8smjfu7zyxjpc@user-gj;language=en,all",
"type": "Neos.Neos.Ui:CopyAfter"
},
{
"payload": {
"baseNodeType": "",
"parentDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"fusionPath": "root<Neos.Fusion:Case>/documentType<Neos.Fusion:Matcher>/element<Webco.Fou001:Document.Article>/body<Neos.Fusion:Array>/content<Webco.Fou001:Component.Template.Article>/main<Neos.Neos:PrimaryContent>/default<Neos.Fusion:Matcher>/renderer"
},
"siblingDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main/node-i888xtewx12b1@user-gj;language=en,all"
}
},
"subject": "/sites/hub/node-qq1qu5bhs68k5/node-np2yc2v4ue6jf/node-ki3oy5drp9bv4/node-bi4u02u3lhfm4/main/node-a5991ukjekq57@user-gj;language=en,all",
"type": "Neos.Neos.Ui:CopyAfter"
}
]
}
Mixed in between
{
"changes": [
{
"payload": {
"baseNodeType": "",
"parentContextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"parentDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"fusionPath": "root<Neos.Fusion:Case>/documentType<Neos.Fusion:Matcher>/element<Webco.Fou001:Document.Article>/body<Neos.Fusion:Array>/content<Webco.Fou001:Component.Template.Article>/main<Neos.Neos:PrimaryContent>/default<Neos.Fusion:Matcher>/renderer"
}
},
"subject": "/sites/hub/node-qq1qu5bhs68k5/node-np2yc2v4ue6jf/node-ki3oy5drp9bv4/node-bi4u02u3lhfm4/main/node-8smjfu7zyxjpc@user-gj;language=en,all",
"type": "Neos.Neos.Ui:CopyInto"
},
{
"payload": {
"baseNodeType": "",
"parentContextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"parentDomAddress": {
"contextPath": "/sites/hub/node-u2lv5o25g5ncd/node-2xvtpsap7me4d/node-kyzm5axp32nmn/main@user-gj;language=en,all",
"fusionPath": "root<Neos.Fusion:Case>/documentType<Neos.Fusion:Matcher>/element<Webco.Fou001:Document.Article>/body<Neos.Fusion:Array>/content<Webco.Fou001:Component.Template.Article>/main<Neos.Neos:PrimaryContent>/default<Neos.Fusion:Matcher>/renderer"
}
},
"subject": "/sites/hub/node-qq1qu5bhs68k5/node-np2yc2v4ue6jf/node-ki3oy5drp9bv4/node-bi4u02u3lhfm4/main/node-a5991ukjekq57@user-gj;language=en,all",
"type": "Neos.Neos.Ui:CopyInto"
}
]
}
Affected Versions
Neos: 7.2 - presumably earlier versions
UI:
@markusguenther Maybe we can provide a PR for this, at least for some parts of it.
But first I would like to know if you, like I do, think the fix should go into the NEOS UI and not in the mentioned service /neos/ui-services/change
.
I ask, because it might be possible to fix this in the service, but imho the service should not make a decision and rearrange the order to insert which might cause more confusion. What do you think?
The actual paste is done by /neos/ui-services/change, but I think the request payload provided has a wrong order. Thus I think it's an issue of the JS part of the neos ui - see below for request details.
We actually found that the payload seems to have the right order. [Edit]: The payload does appear to have a reversed order when the nodes are selected from bottom to top.
The Problem lies within the anchor (siblingDomAddress) beeing used to insert the nodes. The siblingDomAddress passed via each copyAfter event is always the same (as shown in your example above). If we would like to keep the current style of sending multiple copy events we would have to adjust the siblingDomAddress for the n+1 copy events which is not possible as we dont know the sibling which will be created in the future.
To us the solution seems to lie in having a copyAfter event wich can hold multiple copied nodes instead of having multiple events. As far as i can think this should also fix the problem 3.
Tested in Neos 8.1
Running into the same issue when moving nodes in batches.
Workaround for editors: select nodes in bottom to top order when inserting after or top to bottom order when inserting before.
For visualisation, this is the common error encountered. And it is especial noticeable because every step that would lead to the result is exactly as we humans think :D
We select from top to bottom:
We insert after:
But its in reverse:
if it was selected from bottom to top it would be the correct order.
if insert before
would be chosen it would be the correct order.
For extra special effects use command click and select each node in a random pattern, see that pattern be preserved and depending on after or before be reversed.