diff --git a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php index eb1c909dd1..223a4007a3 100644 --- a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php +++ b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php @@ -19,6 +19,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\SubtreeTagging\Dto\SubtreeTag; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; @@ -706,6 +707,33 @@ public function discardWorkspaceAction(WorkspaceName $workspace): void $this->forward('review', null, null, ['workspace' => $workspace->value]); } + /** + * Rebase a workspace + */ + public function rebaseAction(WorkspaceName $workspaceName, bool $force): void + { + $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest())->contentRepositoryId; + + try { + $this->workspacePublishingService->rebaseWorkspace( + $contentRepositoryId, + $workspaceName, + $force ? RebaseErrorHandlingStrategy::STRATEGY_FORCE : RebaseErrorHandlingStrategy::STRATEGY_FAIL + ); + $this->addFlashMessage($this->getModuleLabel('workspaces.workspaceHasBeenRebased')); + $this->forward('index'); + + } catch (WorkspaceRebaseFailed $e) { + if ($force) { + $this->addFlashMessage($this->getModuleLabel('workspaces.ForceRebaseWorkspaceFailed')); + $this->forward('index'); + } + } + $this->response->addHttpHeader('HX-Retarget', '#popover-container'); + $this->response->addHttpHeader('HX-ReSwap', 'innerHTML'); + $this->view->assign('workspaceName', $workspaceName->value); + } + /** * Computes the number of added, changed and removed nodes for the given workspace */ diff --git a/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Actions/Rebase.fusion b/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Actions/Rebase.fusion new file mode 100644 index 0000000000..a2e4885cea --- /dev/null +++ b/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Actions/Rebase.fusion @@ -0,0 +1,10 @@ +Neos.Workspace.Ui.WorkspaceController.rebase = Neos.Fusion:Component { + /// string + workspaceName = ${workspaceName} + + renderer = afx` + + ` +} diff --git a/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Components/WorkspaceTableRow.fusion b/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Components/WorkspaceTableRow.fusion index 287e3402f2..158120cd87 100644 --- a/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Components/WorkspaceTableRow.fusion +++ b/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Components/WorkspaceTableRow.fusion @@ -59,6 +59,15 @@ prototype(Neos.Workspace.Ui:Component.WorkspaceTableRow) < prototype(Neos.Fusion workspaceName = ${props.workspaceListItem.name} } } + rebaseWorkspaceUri = Neos.Fusion:ActionUri { + action = 'rebase' + format = 'htmx' + arguments { + workspaceName = ${props.workspaceListItem.name} + force = false + } + } + rebaseWorkspacePopoverId = 'workspace-rebase-modal' deleteWorkspacePopoverId = 'workspace-delete-modal' editWorkspacePopoverId = 'workspace-edit-modal' } @@ -131,6 +140,16 @@ prototype(Neos.Workspace.Ui:Component.WorkspaceTableRow) < prototype(Neos.Fusion attributes.hx-swap='innerHTML' attributes.hx-on--after-request={'document.getElementById("' + private.deleteWorkspacePopoverId + '").showPopover()'} /> + ` diff --git a/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Modals/Rebase.fusion b/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Modals/Rebase.fusion new file mode 100644 index 0000000000..509625d7a1 --- /dev/null +++ b/Neos.Workspace.Ui/Resources/Private/Fusion/Features/Workspace/Modals/Rebase.fusion @@ -0,0 +1,57 @@ +prototype(Neos.Workspace.Ui:Component.Modal.Rebase) < prototype(Neos.Fusion:Component) { + /// string + workspaceName = null + + @private { + i18n = ${I18n.id('').source('Main').package('Neos.Workspace.Ui')} + popoverId = 'workspace-rebase-modal' + + forceRebaseWorkspaceUri = Neos.Fusion:ActionUri { + action = 'rebase' + format = 'htmx' + arguments { + workspaceName = ${workspaceName} + force = true + } + } + } + + renderer = afx` +
+
+ +
+ {private.i18n.id('workspaces.dialog.forceSyncWorkspace')} +
+
+
+

{private.i18n.id('workspaces.dialog.thisCanLeadToLostChanges')}

+
+
+ + +
+
+ ` +} diff --git a/Neos.Workspace.Ui/Resources/Private/Translations/en/Main.xlf b/Neos.Workspace.Ui/Resources/Private/Translations/en/Main.xlf index 0af84808b3..86052bd580 100644 --- a/Neos.Workspace.Ui/Resources/Private/Translations/en/Main.xlf +++ b/Neos.Workspace.Ui/Resources/Private/Translations/en/Main.xlf @@ -51,6 +51,9 @@ Edit workspace "{0}" + + Sync workspace "{0}" with its base workspace + Personal workspace @@ -171,6 +174,15 @@ This will delete the workspace including all unpublished content. This operation cannot be undone. + + Syncing has failed + + + A conflict occured while syncing the workspace. Do you want to drop the conflicting changes? + + + Yes, drop changes + This module contains the overview of all elements within the current workspace and it enables to continue the review and publishing workflow for them. @@ -308,6 +320,12 @@ This is the personal workspace of "{0}" + + The workspace has been successfully synced + + + Forcing the sync has failed. Please try discarding your changes. +