From cca575705915704648e54f0fbc37a4357c4c354e Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 15 Feb 2024 14:38:59 +0100 Subject: [PATCH 01/22] TASK: Add E2E test fixture for #3184 --- .../Fixtures/1Dimension/issue-3184.e2e.js | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 Tests/IntegrationTests/Fixtures/1Dimension/issue-3184.e2e.js diff --git a/Tests/IntegrationTests/Fixtures/1Dimension/issue-3184.e2e.js b/Tests/IntegrationTests/Fixtures/1Dimension/issue-3184.e2e.js new file mode 100644 index 0000000000..8e8d20e7b2 --- /dev/null +++ b/Tests/IntegrationTests/Fixtures/1Dimension/issue-3184.e2e.js @@ -0,0 +1,150 @@ +import {beforeEach, checkPropTypes} from './../../utils.js'; +import {Page, PublishDropDown} from './../../pageModel'; +import { Selector } from 'testcafe'; + +/* global fixture:true */ + +// +// Original Issue: https://github.com/neos/neos-ui/issues/3184 +// +fixture`FIX #3184: Discarded node move changes are reflected correctly in the document tree` + .beforeEach(beforeEach) + .afterEach(() => checkPropTypes()); + +// +// This is an excerpt of the document tree in our E2E test distribution, +// stripped down to only show the relevant document nodes for this test +// scenario: +// +// 🗋 Home +// ├─ 🗋 Discarding +// └─ 🗋 Tree multiselect +// ├─ 🗋 MultiA +// ├─ 🗋 MultiB +// └─ 🗋 MultiC +// +// In reference to that hierarchy, we're putting some selectors into variables +// for later use in the concrete test cases, so we don't have to repeat the +// long form over and over: +// +const Discarding = Page.getTreeNodeButton('Discarding'); +const MultiA = Page.getTreeNodeButton('MultiA'); +const MultiB = Page.getTreeNodeButton('MultiB'); +const MultiC = Page.getTreeNodeButton('MultiC'); +const withCmdClick = { + modifiers: { + ctrl: true + } +}; + +test( + 'Scenario #1: Moving nodes and then discarding that change does not lead to an error', + async t => { + // + // Select 🗋 MultiA and 🗋 MultiB, then drag both documents INTO 🗋 MultiC. + // + await t + .click(MultiA) + .click(MultiB, withCmdClick) + .dragToElement(MultiA, MultiC); + + // + // Discard that change. + // + await PublishDropDown.discardAll(); + + // + // Assert that no error flash message shows up. + // + await t + .expect(Selector('[role="alert"][class*="error"]').exists) + .notOk(); + } +); + +test( + 'Scenario #2: Moved nodes do not just disappear after discarding the move change', + async t => { + // + // Select 🗋 MultiA and 🗋 MultiB, then drag both documents INTO 🗋 Discarding. + // + await t + .click(MultiA) + .click(MultiB, withCmdClick) + .dragToElement(MultiA, Discarding); + + // + // Go to 🗋 Tree multiselect, so we can check for stale metadata + // coming from the guest frame. + // We also need to reload to avoid Scenario #1. + // + await Page.goToPage('Tree multiselect'); + await t.eval(() => location.reload(true)); + await Page.waitForIframeLoading(); + + // + // Discard the move change and wait for the guest frame to reload plus + // some extra timeout, so there's a chance for stale metadata to + // overwrite the tree state. + // + await PublishDropDown.discardAll(); + await Page.waitForIframeLoading(); + await t.wait(500); + + // + // Assert that 🗋 MultiA and 🗋 MultiB can still be found. + // + await t + .expect(MultiA.exists) + .ok('🗋 MultiA has disappeared'); + await t + .expect(MultiB.exists) + .ok('🗋 MultiB has disappeared'); + } +) + +test( + 'Scenario #3: Discarding a move change while being on a moved node does not' + + ' lead to an error in the guest frame', + async t => { + // + // Select 🗋 MultiA and 🗋 MultiB, then drag both documents INTO 🗋 MultiC. + // + await t + .click(MultiA) + .click(MultiB, withCmdClick) + .dragToElement(MultiA, MultiC); + + // + // Go to 🗋 Home and reload the backend, so we avoid Scenario #1's + // underlying issue. + // + await Page.goToPage('Home'); + await t.eval(() => location.reload(true)); + + // + // Go to 🗋 MultiA, so we are on a moved node in the guest frame. + // + await Page.goToPage('MultiA'); + + // + // Discard the move change. + // + await PublishDropDown.discardAll(); + + // + // Assert that there's no error showing up in the guest frame and + // that we're instead seeing the next-higher document node. + // + await Page.waitForIframeLoading(); + await t.switchToIframe('[name="neos-content-main"]'); + await t + .expect(Selector('.neos-error-screen').exists) + .notOk('There\'s an unexpected error screen in the guest frame.'); + + await t.switchToMainWindow(); + await t + .expect(Selector('[role="treeitem"] [role="button"][class*="isFocused"]').textContent) + .eql('MultiC'); + } +); From df239206401b395e67a1fd5ed452f4e6fdf93d3e Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 23 May 2023 17:15:14 +0200 Subject: [PATCH 02/22] BUGFIX: Provide better error message if node could not be found on discard --- Classes/Controller/BackendServiceController.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index f78bc2d661..b9f1eca37d 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -276,6 +276,14 @@ public function discardAction(array $nodeContextPaths): void try { foreach ($nodeContextPaths as $contextPath) { $node = $this->nodeService->getNodeFromContextPath($contextPath, null, null, true); + if (!$node) { + $error = new Error(); + $error->setMessage(sprintf('Could not find node for context path "%s"', $contextPath)); + + $this->feedbackCollection->add($error); + continue; + } + if ($node->isRemoved() === true) { // When discarding node removal we should re-create it $updateNodeInfo = new UpdateNodeInfo(); From 859c1f23d3db1666706c091e5394f70c90c92f9c Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Tue, 23 May 2023 17:17:35 +0200 Subject: [PATCH 03/22] BUGFIX: Properly update node info after node move changes have been discarded --- .../ContentRepository/Service/NodeService.php | 19 ++++++++++++++++++- .../Controller/BackendServiceController.php | 14 +++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Classes/ContentRepository/Service/NodeService.php b/Classes/ContentRepository/Service/NodeService.php index 5547b239b8..49ccb8492a 100644 --- a/Classes/ContentRepository/Service/NodeService.php +++ b/Classes/ContentRepository/Service/NodeService.php @@ -128,11 +128,28 @@ public function getNodeFromContextPath($contextPath, Site $site = null, Domain $ * @return boolean */ public function nodeExistsInWorkspace(NodeInterface $node, Workspace $workspace) + { + return $this->getNodeInWorkspace($node, $workspace) !== null; + } + + /** + * Get the variant of the given node in the given workspace + * + * @param NodeInterface $node + * @param Workspace $workspace + * @return NodeInterface|null + */ + public function getNodeInWorkspace(NodeInterface $node, Workspace $workspace): ?NodeInterface { $context = ['workspaceName' => $workspace->getName()]; $flowQuery = new FlowQuery([$node]); - return $flowQuery->context($context)->count() > 0; + $result = $flowQuery->context($context); + if ($result->count() > 0) { + return $result->get(0); + } else { + return null; + } } /** diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index b9f1eca37d..242a73bf4a 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -305,7 +305,19 @@ public function discardAction(array $nodeContextPaths): void $reloadDocument = new ReloadDocument(); $this->feedbackCollection->add($reloadDocument); } - } elseif (!$this->nodeService->nodeExistsInWorkspace($node, $node->getWorkSpace()->getBaseWorkspace())) { + } elseif ($nodeInBaseWorkspace = $this->nodeService->getNodeInWorkspace($node, $node->getWorkSpace()->getBaseWorkspace())) { + $nodeHasBeenMoved = $node->getPath() !== $nodeInBaseWorkspace->getPath(); + if ($nodeHasBeenMoved) { + $removeNode = new RemoveNode(); + $removeNode->setNode($node); + $this->feedbackCollection->add($removeNode); + + $updateNodeInfo = new UpdateNodeInfo(); + $updateNodeInfo->setNode($nodeInBaseWorkspace); + $updateNodeInfo->recursive(); + $this->feedbackCollection->add($updateNodeInfo); + } + } else { // If the node doesn't exist in the target workspace, tell the UI to remove it $removeNode = new RemoveNode(); $removeNode->setNode($node); From 2445c2a7525c11578c9d52f455ac3b7a56ac0e74 Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Wed, 24 May 2023 20:41:12 +0200 Subject: [PATCH 04/22] BUGFIX: Use omniscient content context configuration for node changes --- Classes/ContentRepository/Service/NodeService.php | 1 + Classes/TypeConverter/ChangeCollectionConverter.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/ContentRepository/Service/NodeService.php b/Classes/ContentRepository/Service/NodeService.php index 49ccb8492a..0e725bb277 100644 --- a/Classes/ContentRepository/Service/NodeService.php +++ b/Classes/ContentRepository/Service/NodeService.php @@ -103,6 +103,7 @@ public function getNodeFromContextPath($contextPath, Site $site = null, Domain $ if ($includeAll === true) { $contextProperties['invisibleContentShown'] = true; $contextProperties['removedContentShown'] = true; + $contextProperties['inaccessibleContentShown'] = true; } $context = $this->contextFactory->create( diff --git a/Classes/TypeConverter/ChangeCollectionConverter.php b/Classes/TypeConverter/ChangeCollectionConverter.php index c76b48eb96..3ef27ca101 100644 --- a/Classes/TypeConverter/ChangeCollectionConverter.php +++ b/Classes/TypeConverter/ChangeCollectionConverter.php @@ -137,7 +137,7 @@ protected function convertChangeData($changeData) $changeClassInstance->injectPersistenceManager($this->persistenceManager); $subjectContextPath = $changeData['subject']; - $subject = $this->nodeService->getNodeFromContextPath($subjectContextPath); + $subject = $this->nodeService->getNodeFromContextPath($subjectContextPath, null, null, true); if ($subject instanceof Error) { return $subject; From 302da1d18074efeae17d67a0cc584f60d49c410c Mon Sep 17 00:00:00 2001 From: Wilhelm Behncke Date: Thu, 15 Feb 2024 14:44:50 +0100 Subject: [PATCH 05/22] TASK: Temporarily patch test distribution with neos/neos-development-collection#4291 This needs to be undone before merge --- .../TestDistribution/composer.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Tests/IntegrationTests/TestDistribution/composer.json b/Tests/IntegrationTests/TestDistribution/composer.json index 41fc86012c..5dab4bb15e 100644 --- a/Tests/IntegrationTests/TestDistribution/composer.json +++ b/Tests/IntegrationTests/TestDistribution/composer.json @@ -6,15 +6,27 @@ "vendor-dir": "Packages/Libraries", "bin-dir": "bin", "allow-plugins": { - "neos/composer-plugin": true + "neos/composer-plugin": true, + "cweagans/composer-patches": true } }, "minimum-stability": "dev", "require": { + "neos/neos-development-collection": "8.3.x-dev", "neos/neos-ui": "8.3.x-dev", "neos/fusion-afx": "*", "neos/test-site": "@dev", - "neos/test-nodetypes": "@dev" + "neos/test-nodetypes": "@dev", + + "cweagans/composer-patches": "^1.7.3" + }, + "extra": { + "patches": { + "neos/neos-development-collection": { + "BUGFIX: Invalidate caches correctly after node move changes have been discarded": + "https://github.com/neos/neos-development-collection/pull/4291.patch" + } + } }, "require-dev": { "neos/buildessentials": "@dev", From 58611a8646afdde613f7586b714fc387c569274c Mon Sep 17 00:00:00 2001 From: Michel Loew Date: Wed, 6 Mar 2024 13:48:43 +0100 Subject: [PATCH 06/22] BUGFIX: document-node is redirected to the nearest parent on workspace-change --- .../Controller/BackendServiceController.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index f78bc2d661..0e64c85774 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -345,6 +345,9 @@ public function changeBaseWorkspaceAction(string $targetWorkspaceName, NodeInter throw new Exception('Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first.', 1582800654); } + $sitePath = $documentNode->getContext()->getRootNode()->getPath(); + $originalNodePath = $documentNode->getPath(); + $userWorkspace->setBaseWorkspace($targetWorkspace); $this->workspaceRepository->update($userWorkspace); @@ -357,24 +360,13 @@ public function changeBaseWorkspaceAction(string $targetWorkspaceName, NodeInter $this->feedbackCollection->add($updateWorkspaceInfo); // Construct base workspace context - $originalContext = $documentNode->getContext(); $contextProperties = $documentNode->getContext()->getProperties(); $contextProperties['workspaceName'] = $targetWorkspaceName; $contentContext = $this->contextFactory->create($contextProperties); // If current document node doesn't exist in the base workspace, traverse its parents to find the one that exists - $redirectNode = $documentNode; - while (true) { - $redirectNodeInBaseWorkspace = $contentContext->getNodeByIdentifier($redirectNode->getIdentifier()); - if ($redirectNodeInBaseWorkspace) { - break; - } else { - $redirectNode = $redirectNode->getParent(); - if (!$redirectNode) { - throw new Exception(sprintf('Wasn\'t able to locate any valid node in rootline of node %s in the workspace %s.', $documentNode->getContextPath(), $targetWorkspaceName), 1458814469); - } - } - } + $nodesOnPath = $documentNode->getContext()->getNodesOnPath($sitePath, $originalNodePath); + $redirectNode = $nodesOnPath[count($nodesOnPath) - 1]; // If current document node exists in the base workspace, then reload, else redirect if ($redirectNode === $documentNode) { From 817dad603d014d57424b062f4533c2a3102461f8 Mon Sep 17 00:00:00 2001 From: Michel Loew Date: Wed, 6 Mar 2024 14:02:13 +0100 Subject: [PATCH 07/22] TASK: Remove unnecessary contentContext --- Classes/Controller/BackendServiceController.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index 0e64c85774..5d3ffecc96 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -359,11 +359,6 @@ public function changeBaseWorkspaceAction(string $targetWorkspaceName, NodeInter $updateWorkspaceInfo->setWorkspace($userWorkspace); $this->feedbackCollection->add($updateWorkspaceInfo); - // Construct base workspace context - $contextProperties = $documentNode->getContext()->getProperties(); - $contextProperties['workspaceName'] = $targetWorkspaceName; - $contentContext = $this->contextFactory->create($contextProperties); - // If current document node doesn't exist in the base workspace, traverse its parents to find the one that exists $nodesOnPath = $documentNode->getContext()->getNodesOnPath($sitePath, $originalNodePath); $redirectNode = $nodesOnPath[count($nodesOnPath) - 1]; From 27074c1eb943c539b72df7c7229bc6ccc45900bd Mon Sep 17 00:00:00 2001 From: Michel Loew Date: Wed, 6 Mar 2024 16:05:19 +0100 Subject: [PATCH 08/22] TASK: Definitely fall back to site-node --- Classes/Controller/BackendServiceController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Controller/BackendServiceController.php b/Classes/Controller/BackendServiceController.php index 5d3ffecc96..cca92a59a1 100644 --- a/Classes/Controller/BackendServiceController.php +++ b/Classes/Controller/BackendServiceController.php @@ -345,7 +345,7 @@ public function changeBaseWorkspaceAction(string $targetWorkspaceName, NodeInter throw new Exception('Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first.', 1582800654); } - $sitePath = $documentNode->getContext()->getRootNode()->getPath(); + $sitePath = $documentNode->getContext()->getCurrentSiteNode()->getPath(); $originalNodePath = $documentNode->getPath(); $userWorkspace->setBaseWorkspace($targetWorkspace); @@ -361,7 +361,7 @@ public function changeBaseWorkspaceAction(string $targetWorkspaceName, NodeInter // If current document node doesn't exist in the base workspace, traverse its parents to find the one that exists $nodesOnPath = $documentNode->getContext()->getNodesOnPath($sitePath, $originalNodePath); - $redirectNode = $nodesOnPath[count($nodesOnPath) - 1]; + $redirectNode = array_pop($nodesOnPath) ?? $documentNode->getContext()->getCurrentSiteNode(); // If current document node exists in the base workspace, then reload, else redirect if ($redirectNode === $documentNode) { From 9556324f3a3b11628983712b8ec388263e9817b0 Mon Sep 17 00:00:00 2001 From: Burhan Kiran Date: Sat, 16 Mar 2024 21:18:43 +0100 Subject: [PATCH 09/22] FEATURE: add collapse all button to content&page tree --- .../src/CR/Nodes/selectors.ts | 61 ++++++++++ .../src/UI/ContentTree/index.ts | 25 +++- .../src/UI/PageTree/index.ts | 28 ++++- .../Containers/LeftSideBar/NodeTree/index.js | 113 +++++++++++++----- .../LeftSideBar/NodeTree/style.module.css | 15 +++ 5 files changed, 209 insertions(+), 33 deletions(-) diff --git a/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts b/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts index eed7cf09ea..5284546b83 100644 --- a/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts +++ b/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts @@ -66,6 +66,67 @@ export const makeGetDocumentNodes = (nodeTypesRegistry: NodeTypesRegistry) => cr } ); +export const makeGetCollapsableDocumentNodes = (nodeTypesRegistry: NodeTypesRegistry) => createSelector( + [ + nodesByContextPathSelector + ], + nodesMap => { + const documentRole = nodeTypesRegistry.getRole('document'); + if (!documentRole) { + throw new Error('Document role is not loaded!'); + } + const documentSubNodeTypes = nodeTypesRegistry.getSubTypesOf(documentRole); + + const result: NodeMap = {}; + Object.keys(nodesMap).forEach(contextPath => { + const node = nodesMap[contextPath]; + if (!node) { + throw new Error('This error should never be thrown, it\'s a way to fool TypeScript'); + } + const isCollapsable = node.children.some( + child => child ? documentSubNodeTypes.includes(child.nodeType) : false + ) + if (documentSubNodeTypes.includes(node.nodeType) && isCollapsable) { + result[contextPath] = node; + } + }); + return result; + } +); + +export const makeGetCollapsableContentNodes = (nodeTypesRegistry: NodeTypesRegistry) => createSelector( + [ + nodesByContextPathSelector + ], + nodesMap => { + const contentRole = nodeTypesRegistry.getRole('content'); + const collectionRole = nodeTypesRegistry.getRole('contentCollection'); + if (!contentRole) { + throw new Error('Content role is not loaded!'); + } + if (!collectionRole) { + throw new Error('ContentCollection role is not loaded!'); + } + const contentSubNodeTypes = nodeTypesRegistry.getSubTypesOf(contentRole); + contentSubNodeTypes.push(...nodeTypesRegistry.getSubTypesOf(collectionRole)) + + const result: NodeMap = {}; + Object.keys(nodesMap).forEach(contextPath => { + const node = nodesMap[contextPath]; + if (!node) { + throw new Error('This error should never be thrown, it\'s a way to fool TypeScript'); + } + const isCollapsable = node.children.some( + child => child ? contentSubNodeTypes.includes(child.nodeType) : false + ) + if (contentSubNodeTypes.includes(node.nodeType) && isCollapsable) { + result[contextPath] = node; + } + }); + return result; + } +); + export const makeGetNodeByContextPathSelector = (contextPath: NodeContextPath) => createSelector( [ (state: GlobalState) => $get(['cr', 'nodes', 'byContextPath', contextPath], state) diff --git a/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts b/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts index aa7c933115..1e527398ed 100644 --- a/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts +++ b/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts @@ -31,6 +31,7 @@ export enum actionTypes { REQUEST_CHILDREN = '@neos/neos-ui/UI/ContentTree/REQUEST_CHILDREN', SET_AS_LOADING = '@neos/neos-ui/UI/ContentTree/SET_AS_LOADING', SET_AS_LOADED = '@neos/neos-ui/UI/ContentTree/SET_AS_LOADED', + COLLAPSE_ALL = '@neos/neos-ui/UI/ContentTree/COLLAPSE_ALL' } const toggle = (contextPath: NodeContextPath) => createAction(actionTypes.TOGGLE, contextPath); @@ -40,6 +41,10 @@ const reloadTree = () => createAction(actionTypes.RELOAD_TREE); const requestChildren = (contextPath: NodeContextPath, {unCollapse = true, activate = false} = {}) => createAction(actionTypes.REQUEST_CHILDREN, {contextPath, opts: {unCollapse, activate}}); const setAsLoading = (contextPath: NodeContextPath) => createAction(actionTypes.SET_AS_LOADING, {contextPath}); const setAsLoaded = (contextPath: NodeContextPath) => createAction(actionTypes.SET_AS_LOADED, {contextPath}); +const collapseAll = ( + nodeContextPaths: NodeContextPath[], + collapsedByDefaultNodeContextPaths: NodeContextPath[] +) => createAction(actionTypes.COLLAPSE_ALL, {nodeContextPaths, collapsedByDefaultNodeContextPaths}); // // Export the actions @@ -51,7 +56,8 @@ export const actions = { reloadTree, requestChildren, setAsLoading, - setAsLoaded + setAsLoaded, + collapseAll }; export type Action = ActionType; @@ -89,6 +95,23 @@ export const reducer = (state: State = defaultState, action: InitAction | Action draft.loading = draft.loading.filter(i => i !== contextPath); break; } + case actionTypes.COLLAPSE_ALL: { + const {nodeContextPaths, collapsedByDefaultNodeContextPaths} = action.payload; + + nodeContextPaths.forEach(path => { + if (!draft.toggled.includes(path)) { + draft.toggled.push(path); + } + }); + + collapsedByDefaultNodeContextPaths.forEach(path => { + if (draft.toggled.includes(path)) { + draft.toggled.push(path); + draft.toggled = draft.toggled.filter(i => i !== path); + } + }); + break; + } } }); diff --git a/packages/neos-ui-redux-store/src/UI/PageTree/index.ts b/packages/neos-ui-redux-store/src/UI/PageTree/index.ts index 8b55561600..ee4ae36b13 100644 --- a/packages/neos-ui-redux-store/src/UI/PageTree/index.ts +++ b/packages/neos-ui-redux-store/src/UI/PageTree/index.ts @@ -40,7 +40,8 @@ export enum actionTypes { SET_AS_LOADED = '@neos/neos-ui/UI/PageTree/SET_AS_LOADED', REQUEST_CHILDREN = '@neos/neos-ui/UI/PageTree/REQUEST_CHILDREN', COMMENCE_SEARCH = '@neos/neos-ui/UI/PageTree/COMMENCE_SEARCH', - SET_SEARCH_RESULT = '@neos/neos-ui/UI/PageTree/SET_SEARCH_RESULT' + SET_SEARCH_RESULT = '@neos/neos-ui/UI/PageTree/SET_SEARCH_RESULT', + COLLAPSE_ALL = '@neos/neos-ui/UI/PageTree/COLLAPSE_ALL' } const focus = (contextPath: NodeContextPath, _: undefined, selectionMode: SelectionModeTypes = SelectionModeTypes.SINGLE_SELECT) => createAction(actionTypes.FOCUS, {contextPath, selectionMode}); @@ -49,6 +50,11 @@ const invalidate = (contextPath: NodeContextPath) => createAction(actionTypes.IN const requestChildren = (contextPath: NodeContextPath, {unCollapse = true, activate = false} = {}) => createAction(actionTypes.REQUEST_CHILDREN, {contextPath, opts: {unCollapse, activate}}); const setAsLoading = (contextPath: NodeContextPath) => createAction(actionTypes.SET_AS_LOADING, {contextPath}); const setAsLoaded = (contextPath: NodeContextPath) => createAction(actionTypes.SET_AS_LOADED, {contextPath}); +const collapseAll = ( + nodeContextPaths: NodeContextPath[], + collapsedByDefaultNodeContextPaths: NodeContextPath[] +) => createAction(actionTypes.COLLAPSE_ALL, {nodeContextPaths, collapsedByDefaultNodeContextPaths}); + interface CommenceSearchOptions extends Readonly<{ query: string; filterNodeType: string; @@ -72,7 +78,8 @@ export const actions = { setAsLoaded, requestChildren, commenceSearch, - setSearchResult + setSearchResult, + collapseAll }; export type Action = ActionType; @@ -134,6 +141,23 @@ export const reducer = (state: State = defaultState, action: InitAction | Action draft.filterNodeType = action.payload.filterNodeType; break; } + case actionTypes.COLLAPSE_ALL: { + const {nodeContextPaths, collapsedByDefaultNodeContextPaths} = action.payload; + + nodeContextPaths.forEach(path => { + if (!draft.toggled.includes(path)) { + draft.toggled.push(path); + } + }); + + collapsedByDefaultNodeContextPaths.forEach(path => { + if (draft.toggled.includes(path)) { + draft.toggled.push(path); + draft.toggled = draft.toggled.filter(i => i !== path); + } + }); + break; + } } }); diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index 5efdd420b5..4d2ae6ccbf 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -13,6 +13,7 @@ import {dndTypes} from '@neos-project/neos-ui-constants'; import {PageTreeNode, ContentTreeNode} from './Node/index'; import style from './style.module.css'; +import {neos} from '@neos-project/neos-ui-decorators'; const ConnectedDragLayer = connect((state, {currentlyDraggedNodes}) => { const getNodeByContextPath = selectors.CR.Nodes.nodeByContextPath(state); @@ -28,11 +29,14 @@ export default class NodeTree extends PureComponent { allowOpeningNodesInNewWindow: PropTypes.bool, nodeTypeRole: PropTypes.string, toggle: PropTypes.func, + collapseAll: PropTypes.func, focus: PropTypes.func, requestScrollIntoView: PropTypes.func, setActiveContentCanvasSrc: PropTypes.func, setActiveContentCanvasContextPath: PropTypes.func, - moveNodes: PropTypes.func + moveNodes: PropTypes.func, + allCollapsableNodes: PropTypes.object, + loadingDepth: PropTypes.number }; state = { @@ -45,6 +49,25 @@ export default class NodeTree extends PureComponent { toggle(contextPath); } + handleCollapseAll = () => { + const {collapseAll, allCollapsableNodes, rootNode, loadingDepth} = this.props + let nodeContextPaths = [] + const collapsedByDefaultNodesContextPaths = [] + + Object.values(allCollapsableNodes).forEach(node => { + const collapsedByDefault = loadingDepth === 0 ? false : node.depth - rootNode.depth >= loadingDepth + if (collapsedByDefault) { + collapsedByDefaultNodesContextPaths.push(node.contextPath) + } else { + nodeContextPaths.push(node.contextPath) + } + }); + + // Do not Collapse RootNode + nodeContextPaths = nodeContextPaths.filter(i => i !== rootNode.contextPath); + collapseAll(nodeContextPaths, collapsedByDefaultNodesContextPaths); + } + handleFocus = (contextPath, metaKeyPressed, altKeyPressed, shiftKeyPressed) => { const {focus} = this.props; @@ -123,6 +146,13 @@ export default class NodeTree extends PureComponent { return ( + + Collapse All + ({ - rootNode: selectors.CR.Nodes.siteNodeSelector(state), - focusedNodesContextPaths: selectors.UI.PageTree.getAllFocused(state), - ChildRenderer: PageTreeNode, - allowOpeningNodesInNewWindow: true -}), { - toggle: actions.UI.PageTree.toggle, - focus: actions.UI.PageTree.focus, - setActiveContentCanvasSrc: actions.UI.ContentCanvas.setSrc, - setActiveContentCanvasContextPath: actions.CR.Nodes.setDocumentNode, - moveNodes: actions.CR.Nodes.moveMultiple, - requestScrollIntoView: null -}, (stateProps, dispatchProps, ownProps) => { - return Object.assign({}, stateProps, dispatchProps, ownProps); -})(NodeTree); - -export const ContentTree = connect(state => ({ - rootNode: selectors.CR.Nodes.documentNodeSelector(state), - focusedNodesContextPaths: selectors.CR.Nodes.focusedNodePathsSelector(state), - ChildRenderer: ContentTreeNode, - allowOpeningNodesInNewWindow: false -}), { - toggle: actions.UI.ContentTree.toggle, - focus: actions.CR.Nodes.focus, - moveNodes: actions.CR.Nodes.moveMultiple, - requestScrollIntoView: actions.UI.ContentCanvas.requestScrollIntoView -}, (stateProps, dispatchProps, ownProps) => { - return Object.assign({}, stateProps, dispatchProps, ownProps); -})(NodeTree); +const withNodeTypeRegistry = neos(globalRegistry => ({ + nodeTypesRegistry: globalRegistry.get('@neos-project/neos-ui-contentrepository') +})); + +export const PageTree = withNodeTypeRegistry(connect( + (state, {neos, nodeTypesRegistry}) => { + const documentNodesSelector = selectors.CR.Nodes.makeGetCollapsableDocumentNodes(nodeTypesRegistry); + return ({ + rootNode: selectors.CR.Nodes.siteNodeSelector(state), + focusedNodesContextPaths: selectors.UI.PageTree.getAllFocused(state), + ChildRenderer: PageTreeNode, + allowOpeningNodesInNewWindow: true, + loadingDepth: neos.configuration.structureTree.loadingDepth, + allCollapsableNodes: documentNodesSelector(state) + }) + }, { + toggle: actions.UI.PageTree.toggle, + collapseAll: actions.UI.PageTree.collapseAll, + focus: actions.UI.PageTree.focus, + setActiveContentCanvasSrc: actions.UI.ContentCanvas.setSrc, + setActiveContentCanvasContextPath: actions.CR.Nodes.setDocumentNode, + moveNodes: actions.CR.Nodes.moveMultiple, + requestScrollIntoView: null, + isContentTree: false + }, (stateProps, dispatchProps, ownProps) => { + return Object.assign({}, stateProps, dispatchProps, ownProps); + } +)(NodeTree)); + +export const ContentTree = withNodeTypeRegistry(connect( + (state, {neos, nodeTypesRegistry}) => { + const contentNodesSelector = selectors.CR.Nodes.makeGetCollapsableContentNodes(nodeTypesRegistry); + return ({ + rootNode: selectors.CR.Nodes.documentNodeSelector(state), + focusedNodesContextPaths: selectors.CR.Nodes.focusedNodePathsSelector(state), + ChildRenderer: ContentTreeNode, + allowOpeningNodesInNewWindow: false, + loadingDepth: neos.configuration.structureTree.loadingDepth, + allCollapsableNodes: contentNodesSelector(state) + }) + }, { + toggle: actions.UI.ContentTree.toggle, + collapseAll: actions.UI.ContentTree.collapseAll, + focus: actions.CR.Nodes.focus, + moveNodes: actions.CR.Nodes.moveMultiple, + requestScrollIntoView: actions.UI.ContentCanvas.requestScrollIntoView, + isContentTree: true + }, (stateProps, dispatchProps, ownProps) => { + return Object.assign({}, stateProps, dispatchProps, ownProps); + } +)(NodeTree)); diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css index 96f33a7a7f..cd31d7c8c1 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css @@ -6,7 +6,22 @@ background: var(--colors-ContrastDarker); border-bottom: 1px solid var(--colors-ContrastDark); border-right: 1px solid var(--colors-ContrastDark); + position: relative; } .loader { margin: var(--spacing-Quarter); } +.collapseAll { + position: absolute; + right: 0; + top: 0; + opacity: .5; + text-align: center; + cursor: pointer; + z-index: 5; + padding: 10px 5px 0 5px; + + &:hover { + color: var(--colors-PrimaryBlueHover); + } +} From 4e4b84d6c217f6cafc964482561b23c304e04865 Mon Sep 17 00:00:00 2001 From: Burhan Kiran Date: Sat, 16 Mar 2024 22:54:35 +0100 Subject: [PATCH 10/22] remove accidental lines --- packages/neos-ui-redux-store/src/UI/ContentTree/index.ts | 1 - packages/neos-ui-redux-store/src/UI/PageTree/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts b/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts index 1e527398ed..f541403315 100644 --- a/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts +++ b/packages/neos-ui-redux-store/src/UI/ContentTree/index.ts @@ -106,7 +106,6 @@ export const reducer = (state: State = defaultState, action: InitAction | Action collapsedByDefaultNodeContextPaths.forEach(path => { if (draft.toggled.includes(path)) { - draft.toggled.push(path); draft.toggled = draft.toggled.filter(i => i !== path); } }); diff --git a/packages/neos-ui-redux-store/src/UI/PageTree/index.ts b/packages/neos-ui-redux-store/src/UI/PageTree/index.ts index ee4ae36b13..a321f7a5e3 100644 --- a/packages/neos-ui-redux-store/src/UI/PageTree/index.ts +++ b/packages/neos-ui-redux-store/src/UI/PageTree/index.ts @@ -152,7 +152,6 @@ export const reducer = (state: State = defaultState, action: InitAction | Action collapsedByDefaultNodeContextPaths.forEach(path => { if (draft.toggled.includes(path)) { - draft.toggled.push(path); draft.toggled = draft.toggled.filter(i => i !== path); } }); From acabf39b763ea2f53b7cec60130191b5eecc7925 Mon Sep 17 00:00:00 2001 From: Burhan Abdullah Kiran Date: Sat, 23 Mar 2024 15:24:38 +0100 Subject: [PATCH 11/22] adjust wording to collapsible --- .../neos-ui-redux-store/src/CR/Nodes/selectors.ts | 12 ++++++------ .../src/Containers/LeftSideBar/NodeTree/index.js | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts b/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts index 5284546b83..e45df536af 100644 --- a/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts +++ b/packages/neos-ui-redux-store/src/CR/Nodes/selectors.ts @@ -66,7 +66,7 @@ export const makeGetDocumentNodes = (nodeTypesRegistry: NodeTypesRegistry) => cr } ); -export const makeGetCollapsableDocumentNodes = (nodeTypesRegistry: NodeTypesRegistry) => createSelector( +export const makeGetCollapsibleDocumentNodes = (nodeTypesRegistry: NodeTypesRegistry) => createSelector( [ nodesByContextPathSelector ], @@ -83,10 +83,10 @@ export const makeGetCollapsableDocumentNodes = (nodeTypesRegistry: NodeTypesRegi if (!node) { throw new Error('This error should never be thrown, it\'s a way to fool TypeScript'); } - const isCollapsable = node.children.some( + const isCollapsible = node.children.some( child => child ? documentSubNodeTypes.includes(child.nodeType) : false ) - if (documentSubNodeTypes.includes(node.nodeType) && isCollapsable) { + if (documentSubNodeTypes.includes(node.nodeType) && isCollapsible) { result[contextPath] = node; } }); @@ -94,7 +94,7 @@ export const makeGetCollapsableDocumentNodes = (nodeTypesRegistry: NodeTypesRegi } ); -export const makeGetCollapsableContentNodes = (nodeTypesRegistry: NodeTypesRegistry) => createSelector( +export const makeGetCollapsibleContentNodes = (nodeTypesRegistry: NodeTypesRegistry) => createSelector( [ nodesByContextPathSelector ], @@ -116,10 +116,10 @@ export const makeGetCollapsableContentNodes = (nodeTypesRegistry: NodeTypesRegis if (!node) { throw new Error('This error should never be thrown, it\'s a way to fool TypeScript'); } - const isCollapsable = node.children.some( + const isCollapsible = node.children.some( child => child ? contentSubNodeTypes.includes(child.nodeType) : false ) - if (contentSubNodeTypes.includes(node.nodeType) && isCollapsable) { + if (contentSubNodeTypes.includes(node.nodeType) && isCollapsible) { result[contextPath] = node; } }); diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index 4d2ae6ccbf..e92fff8fdf 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -35,7 +35,7 @@ export default class NodeTree extends PureComponent { setActiveContentCanvasSrc: PropTypes.func, setActiveContentCanvasContextPath: PropTypes.func, moveNodes: PropTypes.func, - allCollapsableNodes: PropTypes.object, + allCollapsibleNodes: PropTypes.object, loadingDepth: PropTypes.number }; @@ -50,11 +50,11 @@ export default class NodeTree extends PureComponent { } handleCollapseAll = () => { - const {collapseAll, allCollapsableNodes, rootNode, loadingDepth} = this.props + const {collapseAll, allCollapsibleNodes, rootNode, loadingDepth} = this.props let nodeContextPaths = [] const collapsedByDefaultNodesContextPaths = [] - Object.values(allCollapsableNodes).forEach(node => { + Object.values(allCollapsibleNodes).forEach(node => { const collapsedByDefault = loadingDepth === 0 ? false : node.depth - rootNode.depth >= loadingDepth if (collapsedByDefault) { collapsedByDefaultNodesContextPaths.push(node.contextPath) @@ -183,14 +183,14 @@ const withNodeTypeRegistry = neos(globalRegistry => ({ export const PageTree = withNodeTypeRegistry(connect( (state, {neos, nodeTypesRegistry}) => { - const documentNodesSelector = selectors.CR.Nodes.makeGetCollapsableDocumentNodes(nodeTypesRegistry); + const documentNodesSelector = selectors.CR.Nodes.makeGetCollapsibleDocumentNodes(nodeTypesRegistry); return ({ rootNode: selectors.CR.Nodes.siteNodeSelector(state), focusedNodesContextPaths: selectors.UI.PageTree.getAllFocused(state), ChildRenderer: PageTreeNode, allowOpeningNodesInNewWindow: true, loadingDepth: neos.configuration.structureTree.loadingDepth, - allCollapsableNodes: documentNodesSelector(state) + allCollapsibleNodes: documentNodesSelector(state) }) }, { toggle: actions.UI.PageTree.toggle, @@ -208,14 +208,14 @@ export const PageTree = withNodeTypeRegistry(connect( export const ContentTree = withNodeTypeRegistry(connect( (state, {neos, nodeTypesRegistry}) => { - const contentNodesSelector = selectors.CR.Nodes.makeGetCollapsableContentNodes(nodeTypesRegistry); + const contentNodesSelector = selectors.CR.Nodes.makeGetCollapsibleContentNodes(nodeTypesRegistry); return ({ rootNode: selectors.CR.Nodes.documentNodeSelector(state), focusedNodesContextPaths: selectors.CR.Nodes.focusedNodePathsSelector(state), ChildRenderer: ContentTreeNode, allowOpeningNodesInNewWindow: false, loadingDepth: neos.configuration.structureTree.loadingDepth, - allCollapsableNodes: contentNodesSelector(state) + allCollapsibleNodes: contentNodesSelector(state) }) }, { toggle: actions.UI.ContentTree.toggle, From e4230be01b49e6850eae52af54dedf0fad8fb36c Mon Sep 17 00:00:00 2001 From: Burhan Abdullah Kiran Date: Sat, 23 Mar 2024 16:09:53 +0100 Subject: [PATCH 12/22] adjust styling of collapse all button --- .../neos-ui/src/Containers/LeftSideBar/NodeTree/index.js | 3 ++- .../src/Containers/LeftSideBar/NodeTree/style.module.css | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index e92fff8fdf..5b386a5995 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -150,8 +150,9 @@ export default class NodeTree extends PureComponent { role="button" onClick={this.handleCollapseAll} className={style.collapseAll} + title="Collapse All" > - Collapse All + svg { color: var(--colors-PrimaryBlueHover); } } From d0196eee1357e88799acff8d5f8e022242f155e2 Mon Sep 17 00:00:00 2001 From: Burhan Abdullah Kiran <56877180+Devclaim@users.noreply.github.com> Date: Thu, 28 Mar 2024 21:49:30 +0100 Subject: [PATCH 13/22] Update packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css Co-authored-by: Wilhelm Behncke <2522299+grebaldi@users.noreply.github.com> --- .../src/Containers/LeftSideBar/NodeTree/style.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css index dfb28a1ada..7f95961656 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/style.module.css @@ -18,7 +18,7 @@ opacity: .5; cursor: pointer; z-index: 5; - padding: 8px; + padding: var(--spacing-Half); font-size: 1.4em; &:hover > svg { From 4771f951b2065b21b3621aa0be61291e21991110 Mon Sep 17 00:00:00 2001 From: Burhan Abdullah Kiran Date: Thu, 28 Mar 2024 22:47:59 +0100 Subject: [PATCH 14/22] change from a to button tag and add opacity 1 on hover --- .../src/Containers/LeftSideBar/NodeTree/index.js | 7 +++---- .../LeftSideBar/NodeTree/style.module.css | 13 +++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index 5b386a5995..f4f82ccf67 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -146,14 +146,13 @@ export default class NodeTree extends PureComponent { return ( - - - + + svg { + .collapseAllIcon { + font-size: 1.2em; + } + + &:hover > .collapseAllIcon { color: var(--colors-PrimaryBlueHover); } + + &:hover { + opacity: 1; + } } From 75c09fc0e18d996b8bd4929ee8a2fe39f24f5ec7 Mon Sep 17 00:00:00 2001 From: Burhan Abdullah Kiran Date: Thu, 28 Mar 2024 22:57:49 +0100 Subject: [PATCH 15/22] WIP add translations --- Resources/Private/Translations/de/Main.xlf | 4 ++++ Resources/Private/Translations/en/Main.xlf | 3 +++ .../src/Containers/LeftSideBar/NodeTree/index.js | 16 +++++++++------- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Resources/Private/Translations/de/Main.xlf b/Resources/Private/Translations/de/Main.xlf index 63f94eb18b..7494ff951b 100644 --- a/Resources/Private/Translations/de/Main.xlf +++ b/Resources/Private/Translations/de/Main.xlf @@ -622,6 +622,10 @@ Inside Innen + + Collapse All + Alle Ordner zuklappen + diff --git a/Resources/Private/Translations/en/Main.xlf b/Resources/Private/Translations/en/Main.xlf index 0db6995fa5..4c41c70e7c 100644 --- a/Resources/Private/Translations/en/Main.xlf +++ b/Resources/Private/Translations/en/Main.xlf @@ -374,6 +374,9 @@ For more information about the error please refer to the JavaScript console. + + Collapse All + diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index f4f82ccf67..0e0525292a 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -36,7 +36,8 @@ export default class NodeTree extends PureComponent { setActiveContentCanvasContextPath: PropTypes.func, moveNodes: PropTypes.func, allCollapsibleNodes: PropTypes.object, - loadingDepth: PropTypes.number + loadingDepth: PropTypes.number, + i18nRegistry: PropTypes.object.isRequired }; state = { @@ -131,7 +132,7 @@ export default class NodeTree extends PureComponent { } render() { - const {rootNode, ChildRenderer} = this.props; + const {rootNode, ChildRenderer, i18nRegistry} = this.props; if (!rootNode) { return (
@@ -149,7 +150,7 @@ export default class NodeTree extends PureComponent { @@ -177,11 +178,12 @@ export default class NodeTree extends PureComponent { } } -const withNodeTypeRegistry = neos(globalRegistry => ({ - nodeTypesRegistry: globalRegistry.get('@neos-project/neos-ui-contentrepository') +const withNodeTypeRegistryAndI18nRegistry = neos(globalRegistry => ({ + nodeTypesRegistry: globalRegistry.get('@neos-project/neos-ui-contentrepository'), + i18nRegistry: globalRegistry.get('i18n') })); -export const PageTree = withNodeTypeRegistry(connect( +export const PageTree = withNodeTypeRegistryAndI18nRegistry(connect( (state, {neos, nodeTypesRegistry}) => { const documentNodesSelector = selectors.CR.Nodes.makeGetCollapsibleDocumentNodes(nodeTypesRegistry); return ({ @@ -206,7 +208,7 @@ export const PageTree = withNodeTypeRegistry(connect( } )(NodeTree)); -export const ContentTree = withNodeTypeRegistry(connect( +export const ContentTree = withNodeTypeRegistryAndI18nRegistry(connect( (state, {neos, nodeTypesRegistry}) => { const contentNodesSelector = selectors.CR.Nodes.makeGetCollapsibleContentNodes(nodeTypesRegistry); return ({ From 8fcfe72e5fc1949e89157e5d13c349a5bb85bfa1 Mon Sep 17 00:00:00 2001 From: Burhan Abdullah Kiran <56877180+Devclaim@users.noreply.github.com> Date: Sat, 13 Apr 2024 14:51:31 +0200 Subject: [PATCH 16/22] Update packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js Co-authored-by: Wilhelm Behncke <2522299+grebaldi@users.noreply.github.com> --- packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js index 0e0525292a..813eaf2a52 100644 --- a/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js +++ b/packages/neos-ui/src/Containers/LeftSideBar/NodeTree/index.js @@ -150,7 +150,7 @@ export default class NodeTree extends PureComponent { From 49db1d23e48f3bb774f531f44632cc20588c42f4 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sun, 21 Apr 2024 10:24:26 +0000 Subject: [PATCH 17/22] TASK: Translated using Weblate (Spanish) Currently translated at 100.0% (121 of 121 strings) Translation: Neos/Neos.Ui - Main - 8.3 Translate-URL: https://hosted.weblate.org/projects/neos/neos-ui-main-8-3/es/ --- Resources/Private/Translations/es/Main.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Private/Translations/es/Main.xlf b/Resources/Private/Translations/es/Main.xlf index 0c91d49e6a..c7a62db460 100644 --- a/Resources/Private/Translations/es/Main.xlf +++ b/Resources/Private/Translations/es/Main.xlf @@ -544,7 +544,7 @@ Copy node type to clipboard - Copiar el tipo de nodo al portapapeles + Copiar tipo de nodo al portapapeles From 95a370e93f8e487006d8ab5c60b06630232881da Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 14 May 2024 09:25:35 +0200 Subject: [PATCH 18/22] TASK: Remove obsolete patch for testing --- Tests/IntegrationTests/TestDistribution/composer.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/IntegrationTests/TestDistribution/composer.json b/Tests/IntegrationTests/TestDistribution/composer.json index 5dab4bb15e..deaf995344 100644 --- a/Tests/IntegrationTests/TestDistribution/composer.json +++ b/Tests/IntegrationTests/TestDistribution/composer.json @@ -23,8 +23,6 @@ "extra": { "patches": { "neos/neos-development-collection": { - "BUGFIX: Invalidate caches correctly after node move changes have been discarded": - "https://github.com/neos/neos-development-collection/pull/4291.patch" } } }, From 2169ca450b28233b2fc4f091c28e3cdb1b38e3c6 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 14 May 2024 10:25:59 +0200 Subject: [PATCH 19/22] TASK: Do not commit `Updating composer dependency and npm versions for release of $VERSION` --- Build/Jenkins/release-neos-ui.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Build/Jenkins/release-neos-ui.sh b/Build/Jenkins/release-neos-ui.sh index 0b624ee20a..f9651bf4f4 100755 --- a/Build/Jenkins/release-neos-ui.sh +++ b/Build/Jenkins/release-neos-ui.sh @@ -54,9 +54,8 @@ make test VERSION=$VERSION make bump-version VERSION=$VERSION NPM_TOKEN=$NPM_TOKEN make publish-npm -# add changes to git and push -git add . -git commit -m "Updating composer dependency and npm versions for release of $VERSION" +# we do not commit our working dir (the changes to the `version` field, as they will cause conflicts) +# see https://github.com/neos/neos-ui/issues/3778 git push origin HEAD:$BRANCH git tag -a -m "$VERSION" $VERSION From bae24e8f4967bb64c9142bac6d48934ad670e895 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 14 May 2024 10:28:25 +0200 Subject: [PATCH 20/22] TASK: Remove hardcoded `version` fields from package.json --- package.json | 1 - packages/debug-reason-for-rendering/package.json | 1 - packages/jest-preset-neos-ui/package.json | 1 - packages/neos-ts-interfaces/package.json | 1 - packages/neos-ui-backend-connector/package.json | 1 - packages/neos-ui-build/package.json | 1 - packages/neos-ui-ckeditor5-bindings/package.json | 1 - packages/neos-ui-constants/package.json | 1 - packages/neos-ui-containers/package.json | 1 - packages/neos-ui-contentrepository/package.json | 1 - packages/neos-ui-decorators/package.json | 1 - packages/neos-ui-editors/package.json | 1 - packages/neos-ui-extensibility-webpack-adapter/package.json | 1 - packages/neos-ui-extensibility/package.json | 1 - packages/neos-ui-guest-frame/package.json | 1 - packages/neos-ui-i18n/package.json | 1 - packages/neos-ui-inspector/package.json | 1 - packages/neos-ui-redux-store/package.json | 1 - packages/neos-ui-sagas/package.json | 1 - packages/neos-ui-validators/package.json | 1 - packages/neos-ui-views/package.json | 1 - packages/neos-ui/package.json | 1 - packages/positional-array-sorter/package.json | 1 - packages/react-proptypes/package.json | 1 - packages/react-ui-components/package.json | 1 - packages/utils-helpers/package.json | 1 - packages/utils-logger/package.json | 1 - packages/utils-redux/package.json | 1 - 28 files changed, 28 deletions(-) diff --git a/package.json b/package.json index 016c41f232..18f96d449a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ "bugs": "https://github.com/neos/neos-ui/issues", "homepage": "https://github.com/neos/neos-ui/blob/master/README.md", "license": "GNU GPLv3", - "version": "8.3.7", "private": true, "resolutions": { "moment": "^2.20.1", diff --git a/packages/debug-reason-for-rendering/package.json b/packages/debug-reason-for-rendering/package.json index 3bd670bf7a..559162b2f4 100644 --- a/packages/debug-reason-for-rendering/package.json +++ b/packages/debug-reason-for-rendering/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/debug-reason-for-rendering", - "version": "8.3.7", "description": "React Performance Optimization Utility - Why does a component re-render?", "repository": "neos/neos-ui", "bugs": "https://github.com/neos/neos-ui/issues", diff --git a/packages/jest-preset-neos-ui/package.json b/packages/jest-preset-neos-ui/package.json index 0463c5d65e..d959df2db4 100644 --- a/packages/jest-preset-neos-ui/package.json +++ b/packages/jest-preset-neos-ui/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/jest-preset-neos-ui", - "version": "8.3.7", "description": "The jest preset for all packages of the neos-ui mono-repo.", "main": "jest-preset.json", "private": true, diff --git a/packages/neos-ts-interfaces/package.json b/packages/neos-ts-interfaces/package.json index 189a597055..0e7eb7538b 100644 --- a/packages/neos-ts-interfaces/package.json +++ b/packages/neos-ts-interfaces/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ts-interfaces", - "version": "8.3.7", "description": "Neos domain-related TypeScript interfaces", "private": true, "main": "src/index.ts", diff --git a/packages/neos-ui-backend-connector/package.json b/packages/neos-ui-backend-connector/package.json index fc515cc1fd..e47a90a42f 100644 --- a/packages/neos-ui-backend-connector/package.json +++ b/packages/neos-ui-backend-connector/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-backend-connector", - "version": "8.3.7", "description": "Endoints and fetch cals to the Neos CMS backend", "private": true, "main": "./src/index.ts", diff --git a/packages/neos-ui-build/package.json b/packages/neos-ui-build/package.json index 9ca0c51991..c9222a197a 100644 --- a/packages/neos-ui-build/package.json +++ b/packages/neos-ui-build/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-build", - "version": "8.3.7", "description": "Bob der Baumeister", "private": true } diff --git a/packages/neos-ui-ckeditor5-bindings/package.json b/packages/neos-ui-ckeditor5-bindings/package.json index 7805b649dc..b386b3b454 100644 --- a/packages/neos-ui-ckeditor5-bindings/package.json +++ b/packages/neos-ui-ckeditor5-bindings/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-ckeditor5-bindings", - "version": "8.3.7", "description": "Prepare CKEditor5 for the Neos CMS UI", "private": true, "main": "./src/manifest.js", diff --git a/packages/neos-ui-constants/package.json b/packages/neos-ui-constants/package.json index e95ec2960c..9f926cfb63 100644 --- a/packages/neos-ui-constants/package.json +++ b/packages/neos-ui-constants/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-constants", - "version": "8.3.7", "description": "Container package to store Neos CMS UI constants", "private": true, "main": "./src/index.js", diff --git a/packages/neos-ui-containers/package.json b/packages/neos-ui-containers/package.json index 020cf01134..a245dd5eb0 100644 --- a/packages/neos-ui-containers/package.json +++ b/packages/neos-ui-containers/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-containers", - "version": "8.3.7", "description": "Smart components for Neos CMS UI.", "private": true, "main": "./src/index.js", diff --git a/packages/neos-ui-contentrepository/package.json b/packages/neos-ui-contentrepository/package.json index 33acf1f51a..b1c231127c 100644 --- a/packages/neos-ui-contentrepository/package.json +++ b/packages/neos-ui-contentrepository/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-contentrepository", - "version": "8.3.7", "description": "Bindings for the Neos ContentRepository", "private": true, "main": "./src/manifest.js", diff --git a/packages/neos-ui-decorators/package.json b/packages/neos-ui-decorators/package.json index 5af1ad95bf..beb73a7822 100644 --- a/packages/neos-ui-decorators/package.json +++ b/packages/neos-ui-decorators/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-decorators", - "version": "8.3.7", "description": "Decorators for Neos CMS UI.", "private": true, "main": "./src/index.ts", diff --git a/packages/neos-ui-editors/package.json b/packages/neos-ui-editors/package.json index fdc66296ef..be904303ca 100644 --- a/packages/neos-ui-editors/package.json +++ b/packages/neos-ui-editors/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-editors", - "version": "8.3.7", "description": "Neos CMS UI Editors for use in the inspector.", "main": "src/manifest.js", "private": true, diff --git a/packages/neos-ui-extensibility-webpack-adapter/package.json b/packages/neos-ui-extensibility-webpack-adapter/package.json index f7624b24cc..b3477845ab 100644 --- a/packages/neos-ui-extensibility-webpack-adapter/package.json +++ b/packages/neos-ui-extensibility-webpack-adapter/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-extensibility-webpack-adapter", - "version": "8.3.7", "description": "Minimal configuration, highly opinionated Webpack 4 + Babel plugin build stack for the Neos CMS UI", "repository": "neos/neos-ui", "bugs": "https://github.com/neos/neos-ui/issues", diff --git a/packages/neos-ui-extensibility/package.json b/packages/neos-ui-extensibility/package.json index 1c1104f806..d7a550dce3 100644 --- a/packages/neos-ui-extensibility/package.json +++ b/packages/neos-ui-extensibility/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-extensibility", - "version": "8.3.7", "description": "Core of the extensibility mechanisms for the Neos UI", "repository": "neos/neos-ui", "bugs": "https://github.com/neos/neos-ui/issues", diff --git a/packages/neos-ui-guest-frame/package.json b/packages/neos-ui-guest-frame/package.json index 3617ec2049..ccf7039647 100644 --- a/packages/neos-ui-guest-frame/package.json +++ b/packages/neos-ui-guest-frame/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-guest-frame", - "version": "8.3.7", "description": "Guest frame initialization bindings", "private": true, "main": "./src/manifest.js", diff --git a/packages/neos-ui-i18n/package.json b/packages/neos-ui-i18n/package.json index dd4227fa9f..d8dd910dbe 100644 --- a/packages/neos-ui-i18n/package.json +++ b/packages/neos-ui-i18n/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-i18n", - "version": "8.3.7", "description": "I18n utilities and components for Neos CMS UI.", "private": true, "main": "./src/index.tsx", diff --git a/packages/neos-ui-inspector/package.json b/packages/neos-ui-inspector/package.json index 116e3b572d..79feee3e82 100644 --- a/packages/neos-ui-inspector/package.json +++ b/packages/neos-ui-inspector/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-inspector", - "version": "8.3.7", "description": "Components for integrating views and editors into the Neos CMS UI inspector.", "private": true, "main": "./src/index.js", diff --git a/packages/neos-ui-redux-store/package.json b/packages/neos-ui-redux-store/package.json index bc3c5f73f4..ae990591e5 100644 --- a/packages/neos-ui-redux-store/package.json +++ b/packages/neos-ui-redux-store/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-redux-store", - "version": "8.3.7", "description": "Redux store implementation for the Neos CMS UI", "private": true, "main": "./src/index.ts", diff --git a/packages/neos-ui-sagas/package.json b/packages/neos-ui-sagas/package.json index 4b2d0dbe3d..bbaa52d1b7 100644 --- a/packages/neos-ui-sagas/package.json +++ b/packages/neos-ui-sagas/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-sagas", - "version": "8.3.7", "description": "Redux Sagas implementation for the Neos CMS UI", "private": true, "main": "src/index.js", diff --git a/packages/neos-ui-validators/package.json b/packages/neos-ui-validators/package.json index 927181349e..6292a74678 100644 --- a/packages/neos-ui-validators/package.json +++ b/packages/neos-ui-validators/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-validators", - "version": "8.3.7", "description": "Validators for Neos CMS UI.", "private": true, "main": "./src/index.ts", diff --git a/packages/neos-ui-views/package.json b/packages/neos-ui-views/package.json index e75390ffd9..a595cf7b0c 100644 --- a/packages/neos-ui-views/package.json +++ b/packages/neos-ui-views/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui-views", - "version": "8.3.7", "description": "Neos CMS UI Views for use in the inspector.", "main": "./src/index.js", "private": true, diff --git a/packages/neos-ui/package.json b/packages/neos-ui/package.json index c7537a03c9..3017ffaa31 100644 --- a/packages/neos-ui/package.json +++ b/packages/neos-ui/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/neos-ui", - "version": "8.3.7", "description": "Neos CMS UI written in ReactJS and a ton of other fun technology.", "private": true, "devDependencies": { diff --git a/packages/positional-array-sorter/package.json b/packages/positional-array-sorter/package.json index d028ee1288..853b0e4cad 100644 --- a/packages/positional-array-sorter/package.json +++ b/packages/positional-array-sorter/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/positional-array-sorter", - "version": "8.3.7", "description": "Flexible array sorter that sorts an array according to a 'position' meta data.", "repository": "neos/neos-ui", "bugs": "https://github.com/neos/neos-ui/issues", diff --git a/packages/react-proptypes/package.json b/packages/react-proptypes/package.json index 747b08e3e2..109bbbe1b5 100644 --- a/packages/react-proptypes/package.json +++ b/packages/react-proptypes/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/react-proptypes", - "version": "8.3.7", "description": "Neos CMS specific proptypes for react", "private": true, "main": "./src/index.js", diff --git a/packages/react-ui-components/package.json b/packages/react-ui-components/package.json index 922e80ed81..efd9f77a3a 100644 --- a/packages/react-ui-components/package.json +++ b/packages/react-ui-components/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/react-ui-components", - "version": "8.3.7", "description": "The UI components which power the Neos backend application.", "repository": "neos/neos-ui", "bugs": "https://github.com/neos/neos-ui/issues", diff --git a/packages/utils-helpers/package.json b/packages/utils-helpers/package.json index 7bba93fb5a..e7f30a340a 100644 --- a/packages/utils-helpers/package.json +++ b/packages/utils-helpers/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/utils-helpers", - "version": "8.3.7", "description": "Helper functions for Neos CMS UI.", "private": true, "main": "./src/index.ts", diff --git a/packages/utils-logger/package.json b/packages/utils-logger/package.json index 28ea7aaf35..1366a6cfea 100644 --- a/packages/utils-logger/package.json +++ b/packages/utils-logger/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/utils-logger", - "version": "8.3.7", "description": "Logger implementation for Neos CMS UI.", "private": true, "main": "./src/index.ts", diff --git a/packages/utils-redux/package.json b/packages/utils-redux/package.json index 582fcf0598..3d2e893102 100644 --- a/packages/utils-redux/package.json +++ b/packages/utils-redux/package.json @@ -1,6 +1,5 @@ { "name": "@neos-project/utils-redux", - "version": "8.3.7", "description": "Neos CMS UI Redux Helper utilitites", "private": true, "main": "./src/index.ts", From 343101d531e69c16a7482242f03442987dbfef57 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 14 May 2024 10:52:01 +0200 Subject: [PATCH 21/22] TASK: Do not push branch --- Build/Jenkins/release-neos-ui.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/Build/Jenkins/release-neos-ui.sh b/Build/Jenkins/release-neos-ui.sh index f9651bf4f4..786d0e4fb3 100755 --- a/Build/Jenkins/release-neos-ui.sh +++ b/Build/Jenkins/release-neos-ui.sh @@ -57,6 +57,5 @@ VERSION=$VERSION NPM_TOKEN=$NPM_TOKEN make publish-npm # we do not commit our working dir (the changes to the `version` field, as they will cause conflicts) # see https://github.com/neos/neos-ui/issues/3778 -git push origin HEAD:$BRANCH git tag -a -m "$VERSION" $VERSION git push origin $VERSION From 9b5576ea79cf2134932b4fb5117e7ab7e8ca0278 Mon Sep 17 00:00:00 2001 From: mhsdesign <85400359+mhsdesign@users.noreply.github.com> Date: Tue, 14 May 2024 11:48:57 +0200 Subject: [PATCH 22/22] TASK: Ensure in ci that .yarn/cache is always up-to-date --- .github/workflows/build_and_test.yml | 4 ++-- Makefile | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 6457ef1e2e..0e7ba9da77 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -18,7 +18,7 @@ jobs: node-version-file: '.nvmrc' cache: 'yarn' - name: Install - run: make install + run: make install-and-verify - name: Lint run: make lint @@ -32,7 +32,7 @@ jobs: node-version-file: '.nvmrc' cache: 'yarn' - name: Install - run: make install + run: make install-and-verify - name: Build run: make build-production - name: Test diff --git a/Makefile b/Makefile index a5715b46ef..a00a4dcea1 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,10 @@ check-requirements: install: ## Install dependencies yarn install +install-and-verify: + # Validate this project because were using Zero-Installs (slightly safer as we accept external PRs) + yarn install --immutable --immutable-cache --check-cache + setup: check-requirements install build ## Run a clean setup @echo Please remember to set frontendDevelopmentMode \ to true in your Settings.yaml.