Skip to content

Commit 9e47fdf

Browse files
committed
Merge remote-tracking branch 'origin/8.4' into 9.0
2 parents 7638e49 + 22cd1c6 commit 9e47fdf

File tree

35 files changed

+943
-64
lines changed

35 files changed

+943
-64
lines changed

Classes/Controller/BackendServiceController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,8 @@ public function flowQueryAction(array $chain): string
710710
),
711711
'getForTreeWithParents' => $nodeInfoHelper->renderNodesWithParents(
712712
array_filter($flowQuery->get()),
713-
$this->request
713+
$this->request,
714+
$finisher['payload']['nodeTypeFilter'] ?? null
714715
),
715716
default => []
716717
};

Classes/Fusion/Helper/NodeInfoHelper.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public function renderNodes(
270270
* @param array<int,?array<string,mixed>> $nodes
271271
* @return array<int,?array<string,mixed>>
272272
*/
273-
public function renderNodesWithParents(array $nodes, ActionRequest $actionRequest): array
273+
public function renderNodesWithParents(array $nodes, ActionRequest $actionRequest, ?string $nodeTypeFilter = null): array
274274
{
275275
// For search operation we want to include all nodes, not respecting the "baseNodeType" setting
276276
$baseNodeTypeOverride = $this->documentNodeTypeRole;
@@ -285,7 +285,7 @@ public function renderNodesWithParents(array $nodes, ActionRequest $actionReques
285285
} elseif ($renderedNode = $this->renderNodeWithMinimalPropertiesAndChildrenInformation(
286286
$node,
287287
$actionRequest,
288-
$baseNodeTypeOverride
288+
$nodeTypeFilter ?? $baseNodeTypeOverride
289289
)) {
290290
$renderedNode['matched'] = true;
291291
$renderedNodes[$node->aggregateId->value] = $renderedNode;
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
import {beforeEach, checkPropTypes} from './../../utils.js';
2+
import {Page} from './../../pageModel';
3+
import {Selector} from 'testcafe';
4+
5+
/* global fixture:true */
6+
7+
fixture`Node Tree Presets`
8+
.beforeEach(beforeEach)
9+
.afterEach(() => checkPropTypes())
10+
.before(async () => {
11+
const response = await fetch('http://127.0.0.1:8081/test/write-additional-settings', {
12+
method: 'POST',
13+
headers: {
14+
'Content-Type': 'application/json'
15+
},
16+
body: JSON.stringify({settings: SETTINGS_WITH_NODE_TREE_PRESETS})
17+
});
18+
const json = await response.json();
19+
if (!('success' in json) || !json.success) {
20+
throw new Error('Additional settings could not be written.');
21+
}
22+
})
23+
.after(async () => {
24+
const response = await fetch('http://127.0.0.1:8081/test/remove-additional-settings', {
25+
method: 'POST'
26+
});
27+
const json = await response.json();
28+
if (!('success' in json) || !json.success) {
29+
throw new Error('Additional settings could not be removed.');
30+
}
31+
});
32+
33+
const SETTINGS_WITH_NODE_TREE_PRESETS = {
34+
Neos: {
35+
Neos: {
36+
userInterface: {
37+
navigateComponent: {
38+
nodeTree: {
39+
loadingDepth: 2,
40+
presets: {
41+
'default': {
42+
baseNodeType: 'Neos.Neos:Document,!Neos.TestNodeTypes:Document.Blog,!Neos.TestNodeTypes:Document.BlogArticle'
43+
},
44+
'blog': {
45+
ui: {
46+
icon: 'newspaper-o',
47+
label: 'Show Blog only'
48+
},
49+
baseNodeType: 'Neos.TestNodeTypes:Document.Blog'
50+
},
51+
'blog-articles': {
52+
ui: {
53+
icon: 'file-text-o',
54+
label: 'Show Blog Articles only'
55+
},
56+
baseNodeType: 'Neos.TestNodeTypes:Document.BlogArticle'
57+
}
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
};
65+
66+
fixture.skip`TODO Reimplement / Fix Node Tree Presets for 9.0 https://github.com/neos/neos-ui/issues/3702`;
67+
68+
test('Node tree preset "default" removes all blog related nodes and only loads nodes with depth <= 2', async (t) => {
69+
//
70+
// Assert that all documents with a depth > 2 are no longer visible in
71+
// "default" preset
72+
//
73+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
74+
.notOk('[🗋 Nested Page #2] can still be found in the document tree with preset "default".');
75+
76+
//
77+
// Assert that all the blog-related documents are not visible in "default"
78+
// preset
79+
//
80+
await t.expect(Page.treeNode.withExactText('Blog').exists)
81+
.notOk('[🗋 Blog] can still be found in the document tree with preset "default".');
82+
await t.expect(Page.treeNode.withExactText('Hello World!').exists)
83+
.notOk('[🗋 Hello World!] can still be found in the document tree with preset "default".');
84+
await t.expect(Page.treeNode.withExactText('Fix all the bugs with this weird little trick!').exists)
85+
.notOk('[🗋 Fix all the bugs with this weird little trick!] can still be found in the document tree with preset "default".');
86+
await t.expect(Page.treeNode.withExactText('Writing Blog Articles considered harmful').exists)
87+
.notOk('[🗋 Writing Blog Articles considered harmful] can still be found in the document tree with preset "default".');
88+
});
89+
90+
test('Node tree preset "blog" shows nothing but page [🗋 Blog]', async (t) => {
91+
await t.click('#btn-ToggleDocumentTreeFilter');
92+
await t.click('#neos-NodeTreeFilter');
93+
await t.click(Selector('[role="button"]').withText('Show Blog only'));
94+
95+
await t.expect(Page.treeNode.withExactText('Blog').exists)
96+
.ok('[🗋 Blog] did not show up after switching to node tree preset "blog".');
97+
});
98+
99+
test('In node tree preset "blog", page [🗋 Blog] has no toggle handle', async (t) => {
100+
await t.click('#btn-ToggleDocumentTreeFilter');
101+
await t.click('#neos-NodeTreeFilter');
102+
await t.click(Selector('[role="button"]').withText('Show Blog only'));
103+
104+
await t.expect(Page.getToggleChildrenButtonOf('Blog').exists)
105+
.notOk('[🗋 Blog] has a toggle handle, even though its children do not match the currently set filter in node tree preset "blog".');
106+
});
107+
108+
test('Reloading the node tree while in preset "blog" results in nothing but page [🗋 Blog]', async (t) => {
109+
await t.click('#btn-ToggleDocumentTreeFilter');
110+
await t.click('#neos-NodeTreeFilter');
111+
await t.click(Selector('[role="button"]').withText('Show Blog only'));
112+
await t.click('#neos-PageTree-RefreshPageTree');
113+
114+
await t.expect(Page.treeNode.withExactText('Blog').exists)
115+
.ok('[🗋 Blog] did not show up after switching to node tree preset "blog".');
116+
});
117+
118+
test('Node tree preset "blog-articles" shows page [🗋 Blog] and all articles beneath it', async (t) => {
119+
await t.click('#btn-ToggleDocumentTreeFilter');
120+
await t.click('#neos-NodeTreeFilter');
121+
await t.click(Selector('[role="button"]').withText('Show Blog Articles only'));
122+
123+
await t.expect(Page.treeNode.withExactText('Blog').exists)
124+
.ok('[🗋 Blog] did not show up after switching to node tree preset "blog-articles".');
125+
await t.expect(Page.treeNode.withExactText('Hello World!').exists)
126+
.ok('[🗋 Hello World!] did not show up after switching to node tree preset "blog-articles".');
127+
await t.expect(Page.treeNode.withExactText('Fix all the bugs with this weird little trick!').exists)
128+
.ok('[🗋 Fix all the bugs with this weird little trick!] did not show up after switching to node tree preset "blog-articles".');
129+
await t.expect(Page.treeNode.withExactText('Writing Blog Articles considered harmful').exists)
130+
.ok('[🗋 Writing Blog Articles considered harmful] did not show up after switching to node tree preset "blog-articles".');
131+
});
132+
133+
//
134+
// Original issue: https://github.com/neos/neos-ui/issues/3816
135+
//
136+
test('BUG #3816: Switching back from node tree preset "blog" does not affect loading children in node tree preset "default"', async (t) => {
137+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
138+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
139+
.ok('[🗋 Nested Page #2] did not show up after toggling children of [🗋 Nested Page #1] the first time.');
140+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
141+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
142+
.notOk('[🗋 Nested Page #2] did not disappear after toggling children of [🗋 Nested Page #1] the second time.');
143+
144+
await t.click('#btn-ToggleDocumentTreeFilter');
145+
await t.click('#neos-NodeTreeFilter');
146+
await t.click(Selector('[role="button"]').withText('Show Blog only'));
147+
await t.expect(Page.treeNode.withExactText('Blog').exists)
148+
.ok('[🗋 Blog] did not show up after switching to node tree preset "blog".');
149+
150+
await t.click('#neos-NodeTreeFilter-SelectBox-btn-reset');
151+
await t.expect(Page.treeNode.withExactText('Blog').exists)
152+
.notOk('[🗋 Blog] did not disappear after switching back to node tree preset "default".');
153+
154+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
155+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
156+
.ok('[🗋 Nested Page #2] did not show up after toggling children of [🗋 Nested Page #1] the third time.');
157+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
158+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
159+
.notOk('[🗋 Nested Page #2] did not disappear after toggling children of [🗋 Nested Page #1] the fourth time.');
160+
});
161+
162+
//
163+
// Original issue: https://github.com/neos/neos-ui/issues/2583
164+
//
165+
test('BUG #2583: Searching the document tree does not break expansion in node tree preset "default"', async (t) => {
166+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
167+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
168+
.ok('[🗋 Nested Page #2] did not show up after toggling children of [🗋 Nested Page #1] the first time.');
169+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
170+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
171+
.notOk('[🗋 Nested Page #2] did not disappear after toggling children of [🗋 Nested Page #1] the second time.');
172+
173+
await t.click('#btn-ToggleDocumentTreeFilter');
174+
175+
await t.typeText(Selector('#neos-NodeTreeSearchInput input[type="search"]'), 'Nested Page #10');
176+
await t.expect(Page.treeNode.withExactText('Nested Page #10').exists)
177+
.ok('[🗋 Nested Page #10] did not show up after searching for "Nested Page #10".');
178+
179+
await t.click('#neos-NodeTreeSearchInput-btn-reset');
180+
await t.expect(Page.treeNode.withExactText('Nested Page #10').exists)
181+
.notOk('[🗋 Nested Page #10] did not disappear after clearing search.');
182+
183+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
184+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
185+
.ok('[🗋 Nested Page #2] did not show up after toggling children of [🗋 Nested Page #1] the third time.');
186+
await t.click(Page.getToggleChildrenButtonOf('Nested Page #1'));
187+
await t.expect(Page.treeNode.withExactText('Nested Page #2').exists)
188+
.notOk('[🗋 Nested Page #2] did not disappear after toggling children of [🗋 Nested Page #1] the fourth time.');
189+
});
190+
191+
//
192+
// Original issue: https://github.com/neos/neos-ui/issues/2800
193+
//
194+
test('BUG #2800 1/2: Moving pages before/after in a filtered view does not lead to the disappearance of nodes', async (t) => {
195+
await t.click('#btn-ToggleDocumentTreeFilter');
196+
await t.click('#neos-NodeTreeFilter');
197+
await t.click(Selector('[role="button"]').withText('Show Blog Articles only'));
198+
199+
//
200+
// Move Blog Article [🗋 Hello World!] before [🗋 Writing Blog Articles considered harmful]
201+
//
202+
await t.dragToElement(
203+
Page.getTreeNodeButton('Hello World!'),
204+
Page.getTreeNodeButton('Writing Blog Articles considered harmful').prevSibling()
205+
);
206+
207+
await t.expect(Page.treeNode.withExactText('Blog').exists)
208+
.ok('[🗋 Blog] disappeared after moving nodes in node tree preset "blog-articles".');
209+
await t.expect(Page.treeNode.withExactText('Hello World!').exists)
210+
.ok('[🗋 Hello World!] disappeared after moving nodes in node tree preset "blog-articles".');
211+
await t.expect(Page.treeNode.withExactText('Fix all the bugs with this weird little trick!').exists)
212+
.ok('[🗋 Fix all the bugs with this weird little trick!] disappeared after moving nodes in node tree preset "blog-articles".');
213+
await t.expect(Page.treeNode.withExactText('Writing Blog Articles considered harmful').exists)
214+
.ok('[🗋 Writing Blog Articles considered harmful] disappeared after moving nodes in node tree preset "blog-articles".');
215+
216+
//
217+
// Move Blog Article [🗋 Hello World!] after [🗋 Writing Blog Articles considered harmful]
218+
//
219+
await t.dragToElement(
220+
Page.getTreeNodeButton('Hello World!'),
221+
Page.getTreeNodeButton('Writing Blog Articles considered harmful').nextSibling()
222+
);
223+
224+
await t.expect(Page.treeNode.withExactText('Blog').exists)
225+
.ok('[🗋 Blog] disappeared after moving nodes in node tree preset "blog-articles".');
226+
await t.expect(Page.treeNode.withExactText('Hello World!').exists)
227+
.ok('[🗋 Hello World!] disappeared after moving nodes in node tree preset "blog-articles".');
228+
await t.expect(Page.treeNode.withExactText('Fix all the bugs with this weird little trick!').exists)
229+
.ok('[🗋 Fix all the bugs with this weird little trick!] disappeared after moving nodes in node tree preset "blog-articles".');
230+
await t.expect(Page.treeNode.withExactText('Writing Blog Articles considered harmful').exists)
231+
.ok('[🗋 Writing Blog Articles considered harmful] disappeared after moving nodes in node tree preset "blog-articles".');
232+
});
233+
234+
test('BUG #2800 2/2: Moving pages into each other in a filtered view does not break expansion', async (t) => {
235+
await t.click('#btn-ToggleDocumentTreeFilter');
236+
await t.click('#neos-NodeTreeFilter');
237+
await t.click(Selector('[role="button"]').withText('Show Blog Articles only'));
238+
239+
//
240+
// Move Blog Article [🗋 Hello World!] into [🗋 Writing Blog Articles considered harmful]
241+
//
242+
await t.dragToElement(
243+
Page.getTreeNodeButton('Hello World!'),
244+
Page.getTreeNodeButton('Writing Blog Articles considered harmful')
245+
);
246+
247+
await t.expect(Page.treeNode.withExactText('Blog').exists)
248+
.ok('[🗋 Blog] disappeared after moving nodes in node tree preset "blog-articles".');
249+
await t.expect(Page.treeNode.withExactText('Fix all the bugs with this weird little trick!').exists)
250+
.ok('[🗋 Fix all the bugs with this weird little trick!] disappeared after moving nodes in node tree preset "blog-articles".');
251+
await t.expect(Page.treeNode.withExactText('Writing Blog Articles considered harmful').exists)
252+
.ok('[🗋 Writing Blog Articles considered harmful] disappeared after moving nodes in node tree preset "blog-articles".');
253+
254+
await t.expect(Page.treeNode.withExactText('Hello World!').exists)
255+
.notOk('[🗋 Hello World!] unexpectedly appeared before uncollapsing [🗋 Writing Blog Articles considered harmful].');
256+
await t.click(Page.getToggleChildrenButtonOf('Writing Blog Articles considered harmful'));
257+
await t.expect(Page.treeNode.withExactText('Hello World!').exists)
258+
.ok('[🗋 Writing Blog Articles considered harmful] cannot be uncollapsed after [🗋 Hello World!] was moved into it in node tree preset "blog-articles".');
259+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Neos.Neos.Ui package.
5+
*
6+
* (c) Contributors of the Neos Project - www.neos.io
7+
*
8+
* This package is Open Source Software. For the full copyright and license
9+
* information, please view the LICENSE file which was distributed with this
10+
* source code.
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Neos\TestNodeTypes\Application\RemoveAdditionalSettings\Controller;
16+
17+
use Neos\Flow\Annotations as Flow;
18+
use Neos\Flow\Mvc\ActionRequest;
19+
use Neos\Flow\Mvc\ActionResponse;
20+
use Neos\Flow\Mvc\Controller\ControllerInterface;
21+
use Neos\TestNodeTypes\Application\RemoveAdditionalSettings\RemoveAdditionalSettingsCommand;
22+
use Neos\TestNodeTypes\Application\RemoveAdditionalSettings\RemoveAdditionalSettingsCommandHandler;
23+
24+
#[Flow\Scope("singleton")]
25+
final class RemoveAdditionalSettingsController implements ControllerInterface
26+
{
27+
#[Flow\Inject]
28+
protected RemoveAdditionalSettingsCommandHandler $commandHandler;
29+
30+
public function processRequest(ActionRequest $request, ActionResponse $response)
31+
{
32+
$request->setDispatched(true);
33+
$response->setContentType('application/json');
34+
35+
try {
36+
$command = RemoveAdditionalSettingsCommand::fromArray($request->getArguments());
37+
$this->commandHandler->handle($command);
38+
39+
$response->setStatusCode(200);
40+
$response->setContent(
41+
json_encode(
42+
['success' => true],
43+
JSON_THROW_ON_ERROR
44+
)
45+
);
46+
} catch (\InvalidArgumentException $e) {
47+
$response->setStatusCode(400);
48+
$response->setContent(
49+
json_encode(
50+
['error' => [
51+
'type' => $e::class,
52+
'code' => $e->getCode(),
53+
'message' => $e->getMessage(),
54+
]],
55+
JSON_THROW_ON_ERROR
56+
)
57+
);
58+
} catch (\Exception $e) {
59+
$response->setStatusCode(500);
60+
$response->setContent(
61+
json_encode(
62+
['error' => [
63+
'type' => $e::class,
64+
'code' => $e->getCode(),
65+
'message' => $e->getMessage(),
66+
]],
67+
JSON_THROW_ON_ERROR
68+
)
69+
);
70+
}
71+
}
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Neos.Neos.Ui package.
5+
*
6+
* (c) Contributors of the Neos Project - www.neos.io
7+
*
8+
* This package is Open Source Software. For the full copyright and license
9+
* information, please view the LICENSE file which was distributed with this
10+
* source code.
11+
*/
12+
13+
declare(strict_types=1);
14+
15+
namespace Neos\TestNodeTypes\Application\RemoveAdditionalSettings;
16+
17+
use Neos\Flow\Annotations as Flow;
18+
19+
#[Flow\Proxy(false)]
20+
final class RemoveAdditionalSettingsCommand
21+
{
22+
public function __construct(
23+
) {
24+
}
25+
26+
public static function fromArray(array $array): self
27+
{
28+
return new self();
29+
}
30+
}

0 commit comments

Comments
 (0)