From c1fe4f53c2b6fc361d4d162dc4d5a4a73db38edd Mon Sep 17 00:00:00 2001 From: pKallert Date: Tue, 10 Dec 2024 11:57:03 +0100 Subject: [PATCH 01/11] Feature: Add basic popup for partial publish --- ...PublishChangesInDocumentCommandHandler.php | 35 ++++-- .../Shared/PartialPublishFailed.php | 36 ++++++ .../Translations/en/PublishingDialog.xlf | 9 ++ .../src/CR/Publishing/index.ts | 17 +++ packages/neos-ui-sagas/src/Publish/index.ts | 7 ++ .../PublishAllConfirmationDialog.tsx | 116 ++++++++++++++++++ .../PublishingDialog/PublishingDialog.tsx | 23 +++- 7 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 Classes/Application/Shared/PartialPublishFailed.php create mode 100644 packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx diff --git a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php index d090fdb815..0119da7c5e 100644 --- a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php +++ b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php @@ -15,6 +15,7 @@ namespace Neos\Neos\Ui\Application\PublishChangesInDocument; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\PartialWorkspaceRebaseFailed; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateCurrentlyDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -23,6 +24,7 @@ use Neos\Neos\Domain\Service\WorkspacePublishingService; use Neos\Neos\Ui\Application\Shared\ConflictsOccurred; use Neos\Neos\Ui\Application\Shared\PublishSucceeded; +use Neos\Neos\Ui\Application\Shared\PartialPublishFailed; use Neos\Neos\Ui\Controller\TranslationTrait; use Neos\Neos\Ui\Infrastructure\ContentRepository\ConflictsFactory; @@ -51,7 +53,8 @@ final class PublishChangesInDocumentCommandHandler */ public function handle( PublishChangesInDocumentCommand $command - ): PublishSucceeded|ConflictsOccurred { + ): PublishSucceeded|ConflictsOccurred|PartialPublishFailed + { try { $publishingResult = $this->workspacePublishingService->publishChangesInDocument( $command->contentRepositoryId, @@ -67,6 +70,25 @@ public function handle( numberOfAffectedChanges: $publishingResult->numberOfPublishedChanges, baseWorkspaceName: $workspace?->baseWorkspaceName?->value ); + } catch (WorkspaceRebaseFailed $e) { + $conflictsFactory = new ConflictsFactory( + contentRepository: $this->contentRepositoryRegistry + ->get($command->contentRepositoryId), + nodeLabelGenerator: $this->nodeLabelGenerator, + workspaceName: $command->workspaceName, + preferredDimensionSpacePoint: $command->preferredDimensionSpacePoint + ); + + return new ConflictsOccurred( + conflicts: $conflictsFactory->fromWorkspaceRebaseFailed($e) + ); + } catch (PartialWorkspaceRebaseFailed $e) { + $workspace = $this->contentRepositoryRegistry->get($command->contentRepositoryId)->findWorkspaceByName( + $command->workspaceName + ); + return new PartialPublishFailed( + baseWorkspaceName: $workspace?->baseWorkspaceName?->value + ); } catch (NodeAggregateCurrentlyDoesNotExist $e) { throw new \RuntimeException( $this->getLabel('NodeNotPublishedMissingParentNode'), @@ -79,18 +101,7 @@ public function handle( 1705053432, $e ); - } catch (WorkspaceRebaseFailed $e) { - $conflictsFactory = new ConflictsFactory( - contentRepository: $this->contentRepositoryRegistry - ->get($command->contentRepositoryId), - nodeLabelGenerator: $this->nodeLabelGenerator, - workspaceName: $command->workspaceName, - preferredDimensionSpacePoint: $command->preferredDimensionSpacePoint - ); - return new ConflictsOccurred( - conflicts: $conflictsFactory->fromWorkspaceRebaseFailed($e) - ); } } } diff --git a/Classes/Application/Shared/PartialPublishFailed.php b/Classes/Application/Shared/PartialPublishFailed.php new file mode 100644 index 0000000000..bbfc4438db --- /dev/null +++ b/Classes/Application/Shared/PartialPublishFailed.php @@ -0,0 +1,36 @@ + get_object_vars($this) + ]; + } +} diff --git a/Resources/Private/Translations/en/PublishingDialog.xlf b/Resources/Private/Translations/en/PublishingDialog.xlf index 3c86b9ce2b..7ca6fab54b 100644 --- a/Resources/Private/Translations/en/PublishingDialog.xlf +++ b/Resources/Private/Translations/en/PublishingDialog.xlf @@ -218,6 +218,15 @@ OK + + Could not publish all changes in "{scopeTitle}" + + + Some changes in this document are dependant on changes in other documents. Do you want to publish all changes to the workspace "{targetWorkspaceName}"? + + + Yes, publish all changes + diff --git a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts index 7191709d60..7bc4e1487a 100644 --- a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts @@ -26,6 +26,7 @@ export enum PublishingPhase { START, ONGOING, CONFLICTS, + PARTIALLYFAILED, SUCCESS, ERROR } @@ -37,6 +38,7 @@ export type State = null | { | { phase: PublishingPhase.START } | { phase: PublishingPhase.ONGOING } | { phase: PublishingPhase.CONFLICTS } + | { phase: PublishingPhase.PARTIALLYFAILED } | { phase: PublishingPhase.ERROR; error: null | AnyError; @@ -56,7 +58,9 @@ export enum actionTypes { CONFLICTS_OCCURRED = '@neos/neos-ui/CR/Publishing/CONFLICTS_OCCURRED', CONFLICTS_RESOLVED = '@neos/neos-ui/CR/Publishing/CONFLICTS_RESOLVED', FAILED = '@neos/neos-ui/CR/Publishing/FAILED', + PARTIALLYFAILED = '@neos/neos-ui/CR/Publishing/PARTIALLYFAILED', RETRIED = '@neos/neos-ui/CR/Publishing/RETRIED', + RETRIEDWITHSTATE = '@neos/neos-ui/CR/Publishing/RETRIEDWITHSTATE', SUCEEDED = '@neos/neos-ui/CR/Publishing/SUCEEDED', ACKNOWLEDGED = '@neos/neos-ui/CR/Publishing/ACKNOWLEDGED', FINISHED = '@neos/neos-ui/CR/Publishing/FINISHED' @@ -94,6 +98,11 @@ const resolveConflicts = () => createAction(actionTypes.CONFLICTS_RESOLVED); const fail = (error: null | AnyError) => createAction(actionTypes.FAILED, {error}); +/** + * Signal that the ongoing publish/discard workflow has partially failed + */ +const partialFail = () => createAction(actionTypes.PARTIALLYFAILED); + /** * Attempt to retry a failed publish/discard workflow */ @@ -125,6 +134,7 @@ export const actions = { conflicts, resolveConflicts, fail, + partialFail, retry, succeed, acknowledge, @@ -183,6 +193,13 @@ export const reducer = (state: State = defaultState, action: Action): State => { error: action.payload.error } }; + case actionTypes.PARTIALLYFAILED: + return { + ...state, + process: { + phase: PublishingPhase.PARTIALLYFAILED + } + }; case actionTypes.RETRIED: return { ...state, diff --git a/packages/neos-ui-sagas/src/Publish/index.ts b/packages/neos-ui-sagas/src/Publish/index.ts index df2c098ee4..34393342f2 100644 --- a/packages/neos-ui-sagas/src/Publish/index.ts +++ b/packages/neos-ui-sagas/src/Publish/index.ts @@ -34,6 +34,11 @@ type PublishingResponse = numberOfAffectedChanges: number; } } + | { + partialPublishFail: { + numberOfAffectedChanges: number; + } + } | { conflicts: Conflict[] } | { error: AnyError }; @@ -131,6 +136,8 @@ export function * watchPublishing({routes}: {routes: Routes}) { } } else if ('error' in result) { yield put(actions.CR.Publishing.fail(result.error)); + } else if ('partialPublishFail' in result) { + yield put(actions.CR.Publishing.partialFail()); } else { yield put(actions.CR.Publishing.fail(null)); } diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx new file mode 100644 index 0000000000..c5714dc40f --- /dev/null +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx @@ -0,0 +1,116 @@ +/* + * This file is part of the Neos.Neos.Ui package. + * + * (c) Contributors of the Neos Project - www.neos.io + * + * This package is Open Source Software. For the full copyright and license + * information, please view the LICENSE file which was distributed with this + * source code. + */ +import React from 'react'; + +import {Button, Dialog, Icon} from '@neos-project/react-ui-components'; +import I18n from '@neos-project/neos-ui-i18n'; +import {PublishingMode, PublishingPhase, PublishingScope} from '@neos-project/neos-ui-redux-store/src/CR/Publishing'; + +import {Diagram} from './Diagram'; + +import style from './style.module.css'; + +type ConfirmationDialogProps = { + mode: PublishingMode; + scope: PublishingScope; + scopeTitle: string; + sourceWorkspaceName: string; + targetWorkspaceName: null | string; + numberOfChanges: number; + onAbort: () => void; + onConfirm: () => void; +} + +export const PublishAllConfirmationDialog: React.FC = (props) => { + const variant = { + id: '', + style: 'error', + icon: { + title: 'exclamation-triangle', + confirm: 'exclamation-triangle' + }, + label: { + title: { + id: 'Neos.Neos.Ui:PublishingDialog:partialPublishFailed.title', + fallback: (props: { scopeTitle: string; }) => + `Could not publish all changes in "${props.scopeTitle}"` + }, + message: { + id: 'Neos.Neos.Ui:PublishingDialog:partialPublishFailed.message', + fallback: (props: { scopeTitle: string; targetWorkspaceName: null | string; }) => + `Some changes in this document are dependent on changes in other documents. Do you want to publish all changes to the workspace "${props.targetWorkspaceName}"?` + }, + cancel: { + id: 'Neos.Neos.Ui:PublishingDialog:publish.all.confirmation.cancel', + fallback: 'No, cancel' + }, + confirm: { + id: 'Neos.Neos.Ui:PublishingDialog:partialPublishFailed.publishAll', + fallback: 'Yes, publish all changes' + } + } + } + + return ( + + + , + + ]} + title={
+ + + + +
} + onRequestClose={props.onAbort} + type={variant.style} + isOpen + autoFocus + theme={undefined as any} + style={undefined as any} + > +
+ + +
+
+ ); +}; diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx index 7997c5916f..25dfa8036d 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx @@ -23,6 +23,7 @@ import { import {ConfirmationDialog} from './ConfirmationDialog'; import {ProcessIndicator} from './ProcessIndicator'; import {ResultDialog} from './ResultDialog'; +import {PublishAllConfirmationDialog} from './PublishAllConfirmationDialog'; const { publishableNodesSelector, @@ -46,6 +47,7 @@ type PublishingDialogHandlers = { confirm: () => void; retry: () => void; acknowledge: () => void; + start: (mode: PublishingMode, scope: PublishingScope) => void; } type PublishingDialogProps = @@ -65,6 +67,11 @@ const PublishingDialog: React.FC = (props) => { props.acknowledge(); }, []); + const handlePublishAllClick = React.useCallback(() => { + props.start(PublishingMode.PUBLISH, PublishingScope.SITE); + props.confirm(); + }, []); + if (props.publishingState === null) { return null; } @@ -114,6 +121,19 @@ const PublishingDialog: React.FC = (props) => { onAcknowledge={handleAcknowledge} /> ); + case PublishingPhase.PARTIALLYFAILED: + return ( + + ); } }; @@ -160,5 +180,6 @@ export default connect((state: GlobalState): PublishingDialogProperties => { confirm: (actions as any).CR.Publishing.confirm, cancel: (actions as any).CR.Publishing.cancel, retry: (actions as any).CR.Publishing.retry, - acknowledge: (actions as any).CR.Publishing.acknowledge + acknowledge: (actions as any).CR.Publishing.acknowledge, + start: (actions as any).CR.Publishing.start })(PublishingDialog); From 7a22dc25b1cfc9033867a65333b566980384881c Mon Sep 17 00:00:00 2001 From: pKallert Date: Mon, 16 Dec 2024 13:28:08 +0100 Subject: [PATCH 02/11] Feature: Use existing conflict dialogue --- ...PublishChangesInDocumentCommandHandler.php | 18 ++- .../Application/Shared/ConflictsOccurred.php | 3 +- .../Shared/PartialPublishFailed.php | 36 ------ .../ContentRepository/ConflictsFactory.php | 18 +++ .../Translations/en/SyncWorkspaceDialog.xlf | 20 +++ .../src/CR/Publishing/index.ts | 17 --- .../src/CR/Syncing/index.ts | 9 +- packages/neos-ui-sagas/src/Publish/index.ts | 6 +- packages/neos-ui-sagas/src/Sync/index.ts | 47 ++++++- .../PublishAllConfirmationDialog.tsx | 116 ------------------ .../PublishingDialog/PublishingDialog.tsx | 23 +--- .../ResolutionStrategyConfirmationDialog.tsx | 72 +++++++++++ .../ResolutionStrategySelectionDialog.tsx | 17 +++ 13 files changed, 193 insertions(+), 209 deletions(-) delete mode 100644 Classes/Application/Shared/PartialPublishFailed.php delete mode 100644 packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx diff --git a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php index 0119da7c5e..78ef6d12cc 100644 --- a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php +++ b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php @@ -24,7 +24,6 @@ use Neos\Neos\Domain\Service\WorkspacePublishingService; use Neos\Neos\Ui\Application\Shared\ConflictsOccurred; use Neos\Neos\Ui\Application\Shared\PublishSucceeded; -use Neos\Neos\Ui\Application\Shared\PartialPublishFailed; use Neos\Neos\Ui\Controller\TranslationTrait; use Neos\Neos\Ui\Infrastructure\ContentRepository\ConflictsFactory; @@ -80,14 +79,21 @@ public function handle( ); return new ConflictsOccurred( - conflicts: $conflictsFactory->fromWorkspaceRebaseFailed($e) + conflicts: $conflictsFactory->fromWorkspaceRebaseFailed($e), + isPartialPublish: false ); } catch (PartialWorkspaceRebaseFailed $e) { - $workspace = $this->contentRepositoryRegistry->get($command->contentRepositoryId)->findWorkspaceByName( - $command->workspaceName + $conflictsFactory = new ConflictsFactory( + contentRepository: $this->contentRepositoryRegistry + ->get($command->contentRepositoryId), + nodeLabelGenerator: $this->nodeLabelGenerator, + workspaceName: $command->workspaceName, + preferredDimensionSpacePoint: $command->preferredDimensionSpacePoint ); - return new PartialPublishFailed( - baseWorkspaceName: $workspace?->baseWorkspaceName?->value + + return new ConflictsOccurred( + conflicts: $conflictsFactory->fromPartialWorkspaceRebaseFailed($e), + isPartialPublish: true ); } catch (NodeAggregateCurrentlyDoesNotExist $e) { throw new \RuntimeException( diff --git a/Classes/Application/Shared/ConflictsOccurred.php b/Classes/Application/Shared/ConflictsOccurred.php index fcf1817f5a..6c721a4b47 100644 --- a/Classes/Application/Shared/ConflictsOccurred.php +++ b/Classes/Application/Shared/ConflictsOccurred.php @@ -23,7 +23,8 @@ final readonly class ConflictsOccurred implements \JsonSerializable { public function __construct( - public readonly Conflicts $conflicts + public readonly Conflicts $conflicts, + public readonly bool $isPartialPublish = true ) { } diff --git a/Classes/Application/Shared/PartialPublishFailed.php b/Classes/Application/Shared/PartialPublishFailed.php deleted file mode 100644 index bbfc4438db..0000000000 --- a/Classes/Application/Shared/PartialPublishFailed.php +++ /dev/null @@ -1,36 +0,0 @@ - get_object_vars($this) - ]; - } -} diff --git a/Classes/Infrastructure/ContentRepository/ConflictsFactory.php b/Classes/Infrastructure/ContentRepository/ConflictsFactory.php index 214e7bcd1c..4a5f768454 100644 --- a/Classes/Infrastructure/ContentRepository/ConflictsFactory.php +++ b/Classes/Infrastructure/ContentRepository/ConflictsFactory.php @@ -29,6 +29,7 @@ use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasTagged; use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasUntagged; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\ConflictingEvent; +use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\PartialWorkspaceRebaseFailed; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Exception\WorkspaceRebaseFailed; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; @@ -87,6 +88,23 @@ public function fromWorkspaceRebaseFailed( return new Conflicts(...$conflictsByKey); } + public function fromPartialWorkspaceRebaseFailed( + PartialWorkspaceRebaseFailed $partialWorkspaceRebaseFailed + ): Conflicts { + /** @var array */ + $conflictsByKey = []; + + foreach ($partialWorkspaceRebaseFailed->conflictingEvents as $conflictingEvent) { + $conflict = $this->createConflict($conflictingEvent); + if (!array_key_exists($conflict->key, $conflictsByKey)) { + // deduplicate if the conflict affects the same node + $conflictsByKey[$conflict->key] = $conflict; + } + } + + return new Conflicts(...$conflictsByKey); + } + private function createConflict( ConflictingEvent $conflictingEvent ): Conflict { diff --git a/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf b/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf index e943c7056a..29f78cdc5e 100644 --- a/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf +++ b/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf @@ -44,6 +44,12 @@ This will discard all changes in your workspace, including those on other sites. + + Publish all changes to workspace "{workspaceName}" + + + This will publish all changes in your workspace, including those on other sites. + Cancel Synchronization @@ -58,12 +64,26 @@ Do you wish to proceed? Be careful: This cannot be undone! + + Publish all changes in workspace "{workspaceName}" + + + You are about to publish all changes in workspace "{workspaceName}". This includes all changes on other sites. + + Do you wish to proceed? Be careful: This cannot be undone! + No, cancel Yes, discard everything + + No, cancel + + + Yes, publish everything + You are about to drop the following changes: diff --git a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts index 7bc4e1487a..7191709d60 100644 --- a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts @@ -26,7 +26,6 @@ export enum PublishingPhase { START, ONGOING, CONFLICTS, - PARTIALLYFAILED, SUCCESS, ERROR } @@ -38,7 +37,6 @@ export type State = null | { | { phase: PublishingPhase.START } | { phase: PublishingPhase.ONGOING } | { phase: PublishingPhase.CONFLICTS } - | { phase: PublishingPhase.PARTIALLYFAILED } | { phase: PublishingPhase.ERROR; error: null | AnyError; @@ -58,9 +56,7 @@ export enum actionTypes { CONFLICTS_OCCURRED = '@neos/neos-ui/CR/Publishing/CONFLICTS_OCCURRED', CONFLICTS_RESOLVED = '@neos/neos-ui/CR/Publishing/CONFLICTS_RESOLVED', FAILED = '@neos/neos-ui/CR/Publishing/FAILED', - PARTIALLYFAILED = '@neos/neos-ui/CR/Publishing/PARTIALLYFAILED', RETRIED = '@neos/neos-ui/CR/Publishing/RETRIED', - RETRIEDWITHSTATE = '@neos/neos-ui/CR/Publishing/RETRIEDWITHSTATE', SUCEEDED = '@neos/neos-ui/CR/Publishing/SUCEEDED', ACKNOWLEDGED = '@neos/neos-ui/CR/Publishing/ACKNOWLEDGED', FINISHED = '@neos/neos-ui/CR/Publishing/FINISHED' @@ -98,11 +94,6 @@ const resolveConflicts = () => createAction(actionTypes.CONFLICTS_RESOLVED); const fail = (error: null | AnyError) => createAction(actionTypes.FAILED, {error}); -/** - * Signal that the ongoing publish/discard workflow has partially failed - */ -const partialFail = () => createAction(actionTypes.PARTIALLYFAILED); - /** * Attempt to retry a failed publish/discard workflow */ @@ -134,7 +125,6 @@ export const actions = { conflicts, resolveConflicts, fail, - partialFail, retry, succeed, acknowledge, @@ -193,13 +183,6 @@ export const reducer = (state: State = defaultState, action: Action): State => { error: action.payload.error } }; - case actionTypes.PARTIALLYFAILED: - return { - ...state, - process: { - phase: PublishingPhase.PARTIALLYFAILED - } - }; case actionTypes.RETRIED: return { ...state, diff --git a/packages/neos-ui-redux-store/src/CR/Syncing/index.ts b/packages/neos-ui-redux-store/src/CR/Syncing/index.ts index ea6b159677..c6f1c7b853 100644 --- a/packages/neos-ui-redux-store/src/CR/Syncing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Syncing/index.ts @@ -24,7 +24,8 @@ export enum SyncingPhase { export enum ResolutionStrategy { FORCE, - DISCARD_ALL + DISCARD_ALL, + PUBLISH_ALL } export enum ReasonForConflict { @@ -106,8 +107,8 @@ const confirm = () => createAction(actionTypes.CONFIRMED); /** * Signal that conflicts occurred during the ongoing syncing (rebasing) workflow */ -const resolve = (conflicts: Conflict[]) => - createAction(actionTypes.CONFLICTS_DETECTED, {conflicts}); +const resolve = (conflicts: Conflict[], strategy: ResolutionStrategy) => + createAction(actionTypes.CONFLICTS_DETECTED, {conflicts, strategy}); /** * Initiates the process of resolving a conflict that occurred @@ -192,7 +193,7 @@ export const reducer = (state: State = defaultState, action: Action): State => { process: { phase: SyncingPhase.CONFLICT, conflicts: action.payload.conflicts, - strategy: null + strategy: action.payload.strategy } }; } diff --git a/packages/neos-ui-sagas/src/Publish/index.ts b/packages/neos-ui-sagas/src/Publish/index.ts index 34393342f2..91c57b5112 100644 --- a/packages/neos-ui-sagas/src/Publish/index.ts +++ b/packages/neos-ui-sagas/src/Publish/index.ts @@ -36,10 +36,10 @@ type PublishingResponse = } | { partialPublishFail: { - numberOfAffectedChanges: number; + conflicts: Conflict[]; } } - | { conflicts: Conflict[] } + | { conflicts: Conflict[], isPartialPublish: boolean } | { error: AnyError }; export function * watchPublishing({routes}: {routes: Routes}) { @@ -109,7 +109,7 @@ export function * watchPublishing({routes}: {routes: Routes}) { } else if ('conflicts' in result) { yield put(actions.CR.Publishing.conflicts()); const conflictsWereResolved: boolean = - yield * resolveConflicts(result.conflicts); + yield * resolveConflicts(result.conflicts, result.isPartialPublish); if (conflictsWereResolved) { yield put(actions.CR.Publishing.resolveConflicts()); diff --git a/packages/neos-ui-sagas/src/Sync/index.ts b/packages/neos-ui-sagas/src/Sync/index.ts index a6f2fca4ab..fccac1f665 100644 --- a/packages/neos-ui-sagas/src/Sync/index.ts +++ b/packages/neos-ui-sagas/src/Sync/index.ts @@ -28,7 +28,7 @@ const handleWindowBeforeUnload = (event: BeforeUnloadEvent) => { type SyncWorkspaceResult = | { success: true } - | { conflicts: Conflict[] } + | { conflicts: Conflict[], isPartialPublish: false } | { error: AnyError }; export function * watchSyncing({routes}: {routes: Routes}) { @@ -75,7 +75,7 @@ export const makeSyncPersonalWorkspace = (deps: { yield * refreshAfterSyncing(); yield put(actions.CR.Syncing.succeed()); } else if ('conflicts' in result) { - yield * resolveConflicts(result.conflicts); + yield * resolveConflicts(result.conflicts, result.isPartialPublish); } else { yield put(actions.CR.Syncing.fail(result.error)); } @@ -93,10 +93,12 @@ export const makeResolveConflicts = (deps: { syncPersonalWorkspace: ReturnType }) => { const discardAll = makeDiscardAll(deps); + const publishAll = makePublishAll(deps); - function * resolveConflicts(conflicts: Conflict[]): any { + function * resolveConflicts(conflicts: Conflict[], isPartialPublish: boolean): any { while (true) { - yield put(actions.CR.Syncing.resolve(conflicts)); + const defaultResolutionStrategy = isPartialPublish ? ResolutionStrategy.PUBLISH_ALL : ResolutionStrategy.FORCE + yield put(actions.CR.Syncing.resolve(conflicts, defaultResolutionStrategy)); const {started}: { cancelled: null | ReturnType; @@ -122,6 +124,11 @@ export const makeResolveConflicts = (deps: { yield * discardAll(); return true; } + + if (strategy === ResolutionStrategy.PUBLISH_ALL) { + yield * publishAll(); + return true; + } } return false; @@ -187,6 +194,38 @@ const makeDiscardAll = (deps: { return discardAll; } +const makePublishAll = (deps: { + syncPersonalWorkspace: ReturnType; +}) => { + function * publishAll() { + yield put(actions.CR.Publishing.start( + PublishingMode.PUBLISH, + PublishingScope.ALL + )); + + const {cancelled, failed}: { + cancelled: null | ReturnType; + failed: null | ReturnType; + finished: null | ReturnType; + } = yield race({ + cancelled: take(actionTypes.CR.Publishing.CANCELLED), + failed: take(actionTypes.CR.Publishing.FAILED), + finished: take(actionTypes.CR.Publishing.FINISHED) + }); + + if (cancelled) { + yield put(actions.CR.Syncing.cancelResolution()); + } else if (failed) { + yield put(actions.CR.Syncing.finish()); + } else { + yield put(actions.CR.Syncing.confirmResolution()); + yield * deps.syncPersonalWorkspace(false); + } + } + + return publishAll; +} + const makeRefreshAfterSyncing = (deps: { routes: Routes }) => { diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx deleted file mode 100644 index c5714dc40f..0000000000 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllConfirmationDialog.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of the Neos.Neos.Ui package. - * - * (c) Contributors of the Neos Project - www.neos.io - * - * This package is Open Source Software. For the full copyright and license - * information, please view the LICENSE file which was distributed with this - * source code. - */ -import React from 'react'; - -import {Button, Dialog, Icon} from '@neos-project/react-ui-components'; -import I18n from '@neos-project/neos-ui-i18n'; -import {PublishingMode, PublishingPhase, PublishingScope} from '@neos-project/neos-ui-redux-store/src/CR/Publishing'; - -import {Diagram} from './Diagram'; - -import style from './style.module.css'; - -type ConfirmationDialogProps = { - mode: PublishingMode; - scope: PublishingScope; - scopeTitle: string; - sourceWorkspaceName: string; - targetWorkspaceName: null | string; - numberOfChanges: number; - onAbort: () => void; - onConfirm: () => void; -} - -export const PublishAllConfirmationDialog: React.FC = (props) => { - const variant = { - id: '', - style: 'error', - icon: { - title: 'exclamation-triangle', - confirm: 'exclamation-triangle' - }, - label: { - title: { - id: 'Neos.Neos.Ui:PublishingDialog:partialPublishFailed.title', - fallback: (props: { scopeTitle: string; }) => - `Could not publish all changes in "${props.scopeTitle}"` - }, - message: { - id: 'Neos.Neos.Ui:PublishingDialog:partialPublishFailed.message', - fallback: (props: { scopeTitle: string; targetWorkspaceName: null | string; }) => - `Some changes in this document are dependent on changes in other documents. Do you want to publish all changes to the workspace "${props.targetWorkspaceName}"?` - }, - cancel: { - id: 'Neos.Neos.Ui:PublishingDialog:publish.all.confirmation.cancel', - fallback: 'No, cancel' - }, - confirm: { - id: 'Neos.Neos.Ui:PublishingDialog:partialPublishFailed.publishAll', - fallback: 'Yes, publish all changes' - } - } - } - - return ( - - - , - - ]} - title={
- - - - -
} - onRequestClose={props.onAbort} - type={variant.style} - isOpen - autoFocus - theme={undefined as any} - style={undefined as any} - > -
- - -
-
- ); -}; diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx index 25dfa8036d..7997c5916f 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx @@ -23,7 +23,6 @@ import { import {ConfirmationDialog} from './ConfirmationDialog'; import {ProcessIndicator} from './ProcessIndicator'; import {ResultDialog} from './ResultDialog'; -import {PublishAllConfirmationDialog} from './PublishAllConfirmationDialog'; const { publishableNodesSelector, @@ -47,7 +46,6 @@ type PublishingDialogHandlers = { confirm: () => void; retry: () => void; acknowledge: () => void; - start: (mode: PublishingMode, scope: PublishingScope) => void; } type PublishingDialogProps = @@ -67,11 +65,6 @@ const PublishingDialog: React.FC = (props) => { props.acknowledge(); }, []); - const handlePublishAllClick = React.useCallback(() => { - props.start(PublishingMode.PUBLISH, PublishingScope.SITE); - props.confirm(); - }, []); - if (props.publishingState === null) { return null; } @@ -121,19 +114,6 @@ const PublishingDialog: React.FC = (props) => { onAcknowledge={handleAcknowledge} /> ); - case PublishingPhase.PARTIALLYFAILED: - return ( - - ); } }; @@ -180,6 +160,5 @@ export default connect((state: GlobalState): PublishingDialogProperties => { confirm: (actions as any).CR.Publishing.confirm, cancel: (actions as any).CR.Publishing.cancel, retry: (actions as any).CR.Publishing.retry, - acknowledge: (actions as any).CR.Publishing.acknowledge, - start: (actions as any).CR.Publishing.start + acknowledge: (actions as any).CR.Publishing.acknowledge })(PublishingDialog); diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx index c0e67a104a..139f4d76ad 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx @@ -34,6 +34,9 @@ export const ResolutionStrategyConfirmationDialog: React.FC<{ switch (props.strategy) { case ResolutionStrategy.FORCE: return (); + + case ResolutionStrategy.PUBLISH_ALL: + return (); case ResolutionStrategy.DISCARD_ALL: default: return (); @@ -182,3 +185,72 @@ const DiscardAllConfirmationDialog: React.FC<{ ); } +const PublishAllConfirmationDialog: React.FC<{ + workspaceName: WorkspaceName; + totalNumberOfChangesInWorkspace: number; + onCancelConflictResolution: () => void; + onConfirmResolutionStrategy: () => void; +}> = (props) => { + return ( + + + , + + ]} + title={ +
+ + +
+ } + onRequestClose={props.onCancelConflictResolution} + type="error" + isOpen + autoFocus + theme={undefined as any} + style={undefined as any} + > +
+ + +
+
+ ); +} diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx index c4feb6f686..f086027b1a 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx @@ -47,6 +47,20 @@ const VARIANTS_BY_RESOLUTION_STRATEGY = { fallback: 'This will discard all changes in your workspace, including those on other sites.' } } + }, + [ResolutionStrategy.PUBLISH_ALL]: { + icon: 'check-double', + labels: { + label: { + id: 'Neos.Neos.Ui:SyncWorkspaceDialog:resolutionStrategy.selection.option.PUBLISH_ALL.label', + fallback: (props: {workspaceName: WorkspaceName}) => + `Publish all changes in workspace "${props.workspaceName}"` + }, + description: { + id: 'Neos.Neos.Ui:SyncWorkspaceDialog:resolutionStrategy.selection.option.PUBLISH_ALL.description', + fallback: 'This will publish all changes in your workspace, including those on other sites.' + } + } } } as const; @@ -56,6 +70,9 @@ const OPTIONS_FOR_RESOLUTION_STRATEGY_SELECTION = [ }, { value: ResolutionStrategy.DISCARD_ALL + }, + { + value: ResolutionStrategy.PUBLISH_ALL } ] as const; From fd81b4d00a3c5bbd0fac693fb622fadb424f7c55 Mon Sep 17 00:00:00 2001 From: pKallert Date: Fri, 20 Dec 2024 08:55:04 +0100 Subject: [PATCH 03/11] Feature: show confirmation dialogue for all resolution strategies --- packages/neos-ui-sagas/src/Publish/index.ts | 9 +---- packages/neos-ui-sagas/src/Sync/index.ts | 38 ++++++++++--------- .../ResolutionStrategyConfirmationDialog.tsx | 5 ++- .../SyncWorkspaceDialog.tsx | 28 ++++++-------- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/packages/neos-ui-sagas/src/Publish/index.ts b/packages/neos-ui-sagas/src/Publish/index.ts index 91c57b5112..65d1a3c9fd 100644 --- a/packages/neos-ui-sagas/src/Publish/index.ts +++ b/packages/neos-ui-sagas/src/Publish/index.ts @@ -34,11 +34,6 @@ type PublishingResponse = numberOfAffectedChanges: number; } } - | { - partialPublishFail: { - conflicts: Conflict[]; - } - } | { conflicts: Conflict[], isPartialPublish: boolean } | { error: AnyError }; @@ -80,6 +75,7 @@ export function * watchPublishing({routes}: {routes: Routes}) { yield takeEvery(actionTypes.CR.Publishing.STARTED, function * publishingWorkflow(action: ReturnType) { const confirmed = yield * waitForConfirmation(); + if (!confirmed) { return; } @@ -97,7 +93,6 @@ export function * watchPublishing({routes}: {routes: Routes}) { const ancestorId: NodeContextPath = ancestorIdSelector ? yield select(ancestorIdSelector) : null; - function * attemptToPublishOrDiscard(): Generator { const result: PublishingResponse = scope === PublishingScope.ALL ? yield call(endpoint as any, workspaceName) @@ -136,8 +131,6 @@ export function * watchPublishing({routes}: {routes: Routes}) { } } else if ('error' in result) { yield put(actions.CR.Publishing.fail(result.error)); - } else if ('partialPublishFail' in result) { - yield put(actions.CR.Publishing.partialFail()); } else { yield put(actions.CR.Publishing.fail(null)); } diff --git a/packages/neos-ui-sagas/src/Sync/index.ts b/packages/neos-ui-sagas/src/Sync/index.ts index fccac1f665..71485c6c48 100644 --- a/packages/neos-ui-sagas/src/Sync/index.ts +++ b/packages/neos-ui-sagas/src/Sync/index.ts @@ -93,7 +93,7 @@ export const makeResolveConflicts = (deps: { syncPersonalWorkspace: ReturnType }) => { const discardAll = makeDiscardAll(deps); - const publishAll = makePublishAll(deps); + const publishAll = makePublishAll(); function * resolveConflicts(conflicts: Conflict[], isPartialPublish: boolean): any { while (true) { @@ -107,10 +107,8 @@ export const makeResolveConflicts = (deps: { cancelled: take(actionTypes.CR.Syncing.CANCELLED), started: take(actionTypes.CR.Syncing.RESOLUTION_STARTED) }); - if (started) { const {payload: {strategy}} = started; - if (strategy === ResolutionStrategy.FORCE) { if (yield * waitForResolutionConfirmation()) { yield * deps.syncPersonalWorkspace(true); @@ -121,13 +119,21 @@ export const makeResolveConflicts = (deps: { } if (strategy === ResolutionStrategy.DISCARD_ALL) { - yield * discardAll(); - return true; + if (yield * waitForResolutionConfirmation()) { + yield * discardAll(); + return true; + } + + continue; } if (strategy === ResolutionStrategy.PUBLISH_ALL) { - yield * publishAll(); - return true; + if (yield * waitForResolutionConfirmation()) { + yield * publishAll(); + return true; + } + + continue; } } @@ -170,7 +176,7 @@ const makeDiscardAll = (deps: { PublishingMode.DISCARD, PublishingScope.ALL )); - + yield put(actions.CR.Publishing.confirm()); const {cancelled, failed}: { cancelled: null | ReturnType; failed: null | ReturnType; @@ -186,7 +192,7 @@ const makeDiscardAll = (deps: { } else if (failed) { yield put(actions.CR.Syncing.finish()); } else { - yield put(actions.CR.Syncing.confirmResolution()); + yield put(actions.CR.Syncing.finish()); yield * deps.syncPersonalWorkspace(false); } } @@ -194,16 +200,14 @@ const makeDiscardAll = (deps: { return discardAll; } -const makePublishAll = (deps: { - syncPersonalWorkspace: ReturnType; -}) => { +const makePublishAll = () => { function * publishAll() { yield put(actions.CR.Publishing.start( PublishingMode.PUBLISH, - PublishingScope.ALL + PublishingScope.SITE )); - - const {cancelled, failed}: { + yield put(actions.CR.Publishing.confirm()); + const {cancelled, failed, finished}: { cancelled: null | ReturnType; failed: null | ReturnType; finished: null | ReturnType; @@ -212,14 +216,12 @@ const makePublishAll = (deps: { failed: take(actionTypes.CR.Publishing.FAILED), finished: take(actionTypes.CR.Publishing.FINISHED) }); - if (cancelled) { yield put(actions.CR.Syncing.cancelResolution()); } else if (failed) { yield put(actions.CR.Syncing.finish()); } else { - yield put(actions.CR.Syncing.confirmResolution()); - yield * deps.syncPersonalWorkspace(false); + yield put(actions.CR.Syncing.finish()); } } diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx index 139f4d76ad..cf95638e20 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx @@ -187,6 +187,7 @@ const DiscardAllConfirmationDialog: React.FC<{ } const PublishAllConfirmationDialog: React.FC<{ workspaceName: WorkspaceName; + baseWorkspaceName: WorkspaceName; totalNumberOfChangesInWorkspace: number; onCancelConflictResolution: () => void; onConfirmResolutionStrategy: () => void; @@ -214,7 +215,7 @@ const PublishAllConfirmationDialog: React.FC<{ onClick={props.onConfirmResolutionStrategy} className={style.button} > - + = (props) => { const handleRetry = React.useCallback(() => { props.retry(); }, []); - switch (props.syncingState?.process.phase) { case SyncingPhase.START: return ( @@ -124,21 +123,18 @@ const SyncWorkspaceDialog: React.FC = (props) => { /> ); case SyncingPhase.RESOLVING: - if (props.syncingState.process.strategy === ResolutionStrategy.FORCE) { - return ( - - ); - } - return null; + return ( + + ); case SyncingPhase.ERROR: case SyncingPhase.SUCCESS: return ( From cec189e04d670a615cae6a37cc5210b952b22fa2 Mon Sep 17 00:00:00 2001 From: pKallert Date: Thu, 2 Jan 2025 10:25:00 +0100 Subject: [PATCH 04/11] Feature: add IDLE status for syncing status --- packages/neos-ui-redux-store/src/CR/Syncing/index.ts | 4 +++- packages/neos-ui-sagas/src/Sync/index.ts | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/neos-ui-redux-store/src/CR/Syncing/index.ts b/packages/neos-ui-redux-store/src/CR/Syncing/index.ts index c6f1c7b853..623ebf0ff5 100644 --- a/packages/neos-ui-redux-store/src/CR/Syncing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Syncing/index.ts @@ -18,6 +18,7 @@ export enum SyncingPhase { ONGOING, CONFLICT, RESOLVING, + IDLE, ERROR, SUCCESS } @@ -65,6 +66,7 @@ export type State = null | { strategy: ResolutionStrategy; conflicts: Conflict[]; } + | { phase: SyncingPhase.IDLE } | { phase: SyncingPhase.ERROR; error: null | AnyError; @@ -247,7 +249,7 @@ export const reducer = (state: State = defaultState, action: Action): State => { return { ...state, process: { - phase: SyncingPhase.ONGOING + phase: SyncingPhase.IDLE } }; case actionTypes.FAILED: diff --git a/packages/neos-ui-sagas/src/Sync/index.ts b/packages/neos-ui-sagas/src/Sync/index.ts index 71485c6c48..54de145c8c 100644 --- a/packages/neos-ui-sagas/src/Sync/index.ts +++ b/packages/neos-ui-sagas/src/Sync/index.ts @@ -93,7 +93,7 @@ export const makeResolveConflicts = (deps: { syncPersonalWorkspace: ReturnType }) => { const discardAll = makeDiscardAll(deps); - const publishAll = makePublishAll(); + const publishAll = makePublishAll(deps); function * resolveConflicts(conflicts: Conflict[], isPartialPublish: boolean): any { while (true) { @@ -132,7 +132,6 @@ export const makeResolveConflicts = (deps: { yield * publishAll(); return true; } - continue; } } @@ -186,7 +185,6 @@ const makeDiscardAll = (deps: { failed: take(actionTypes.CR.Publishing.FAILED), finished: take(actionTypes.CR.Publishing.FINISHED) }); - if (cancelled) { yield put(actions.CR.Syncing.cancelResolution()); } else if (failed) { @@ -200,14 +198,16 @@ const makeDiscardAll = (deps: { return discardAll; } -const makePublishAll = () => { +const makePublishAll = (deps: { + syncPersonalWorkspace: ReturnType; +}) => { function * publishAll() { yield put(actions.CR.Publishing.start( PublishingMode.PUBLISH, PublishingScope.SITE )); yield put(actions.CR.Publishing.confirm()); - const {cancelled, failed, finished}: { + const {cancelled, failed}: { cancelled: null | ReturnType; failed: null | ReturnType; finished: null | ReturnType; @@ -222,6 +222,7 @@ const makePublishAll = () => { yield put(actions.CR.Syncing.finish()); } else { yield put(actions.CR.Syncing.finish()); + yield * deps.syncPersonalWorkspace(false); } } From dc53160f9bbbaad11b1693833e6a2fbe0af9c8a3 Mon Sep 17 00:00:00 2001 From: pKallert Date: Thu, 20 Mar 2025 12:55:06 +0100 Subject: [PATCH 05/11] Fix: Undo changes to sync dialogue --- .../src/CR/Syncing/index.ts | 10 +-- packages/neos-ui-sagas/src/Publish/index.ts | 2 +- packages/neos-ui-sagas/src/Sync/index.ts | 2 - .../ResolutionStrategyConfirmationDialog.tsx | 73 ------------------- .../ResolutionStrategySelectionDialog.tsx | 17 ----- .../SyncWorkspaceDialog.tsx | 26 ++++--- 6 files changed, 20 insertions(+), 110 deletions(-) diff --git a/packages/neos-ui-redux-store/src/CR/Syncing/index.ts b/packages/neos-ui-redux-store/src/CR/Syncing/index.ts index 623ebf0ff5..3ab83ae2de 100644 --- a/packages/neos-ui-redux-store/src/CR/Syncing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Syncing/index.ts @@ -18,7 +18,6 @@ export enum SyncingPhase { ONGOING, CONFLICT, RESOLVING, - IDLE, ERROR, SUCCESS } @@ -66,7 +65,6 @@ export type State = null | { strategy: ResolutionStrategy; conflicts: Conflict[]; } - | { phase: SyncingPhase.IDLE } | { phase: SyncingPhase.ERROR; error: null | AnyError; @@ -109,8 +107,8 @@ const confirm = () => createAction(actionTypes.CONFIRMED); /** * Signal that conflicts occurred during the ongoing syncing (rebasing) workflow */ -const resolve = (conflicts: Conflict[], strategy: ResolutionStrategy) => - createAction(actionTypes.CONFLICTS_DETECTED, {conflicts, strategy}); +const resolve = (conflicts: Conflict[]) => + createAction(actionTypes.CONFLICTS_DETECTED, {conflicts}); /** * Initiates the process of resolving a conflict that occurred @@ -195,7 +193,7 @@ export const reducer = (state: State = defaultState, action: Action): State => { process: { phase: SyncingPhase.CONFLICT, conflicts: action.payload.conflicts, - strategy: action.payload.strategy + strategy: null } }; } @@ -249,7 +247,7 @@ export const reducer = (state: State = defaultState, action: Action): State => { return { ...state, process: { - phase: SyncingPhase.IDLE + phase: SyncingPhase.ONGOING } }; case actionTypes.FAILED: diff --git a/packages/neos-ui-sagas/src/Publish/index.ts b/packages/neos-ui-sagas/src/Publish/index.ts index 6900debf39..b3720f1612 100644 --- a/packages/neos-ui-sagas/src/Publish/index.ts +++ b/packages/neos-ui-sagas/src/Publish/index.ts @@ -146,7 +146,7 @@ export function * watchPublishing({routes}: {routes: Routes}) { } else if ('conflicts' in result) { yield put(actions.CR.Publishing.conflicts()); const conflictsWereResolved: boolean = - yield * resolveConflicts(result.conflicts, result.isPartialPublish); + yield * resolveConflicts(result.conflicts); if (conflictsWereResolved) { yield put(actions.CR.Publishing.resolveConflicts()); diff --git a/packages/neos-ui-sagas/src/Sync/index.ts b/packages/neos-ui-sagas/src/Sync/index.ts index ff4819d5a5..3d5677a206 100644 --- a/packages/neos-ui-sagas/src/Sync/index.ts +++ b/packages/neos-ui-sagas/src/Sync/index.ts @@ -124,8 +124,6 @@ export const makeResolveConflicts = (deps: { yield * discardAll(); return false; // don't continue publishing as this is a deletes all } - - continue; } } diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx index 6a2c88e612..43923d4b52 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategyConfirmationDialog.tsx @@ -34,9 +34,6 @@ export const ResolutionStrategyConfirmationDialog: React.FC<{ switch (props.strategy) { case ResolutionStrategy.FORCE: return (); - - case ResolutionStrategy.PUBLISH_ALL: - return (); case ResolutionStrategy.DISCARD_ALL: default: return (); @@ -185,73 +182,3 @@ const DiscardAllConfirmationDialog: React.FC<{ ); } -const PublishAllConfirmationDialog: React.FC<{ - workspaceName: WorkspaceName; - baseWorkspaceName: WorkspaceName; - totalNumberOfChangesInWorkspace: number; - onCancelConflictResolution: () => void; - onConfirmResolutionStrategy: () => void; -}> = (props) => { - return ( - - - , - - ]} - title={ -
- - -
- } - onRequestClose={props.onCancelConflictResolution} - type="error" - isOpen - autoFocus - theme={undefined as any} - style={undefined as any} - > -
- - -
-
- ); -} diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx index 96a0eb5857..6c46c83095 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/ResolutionStrategySelectionDialog.tsx @@ -47,20 +47,6 @@ const VARIANTS_BY_RESOLUTION_STRATEGY = { fallback: 'This will discard all changes in your workspace, including those on other sites.' } } - }, - [ResolutionStrategy.PUBLISH_ALL]: { - icon: 'check-double', - labels: { - label: { - id: 'Neos.Neos.Ui:SyncWorkspaceDialog:resolutionStrategy.selection.option.PUBLISH_ALL.label', - fallback: (props: {workspaceName: WorkspaceName}) => - `Publish all changes in workspace "${props.workspaceName}"` - }, - description: { - id: 'Neos.Neos.Ui:SyncWorkspaceDialog:resolutionStrategy.selection.option.PUBLISH_ALL.description', - fallback: 'This will publish all changes in your workspace, including those on other sites.' - } - } } } as const; @@ -70,9 +56,6 @@ const OPTIONS_FOR_RESOLUTION_STRATEGY_SELECTION = [ }, { value: ResolutionStrategy.DISCARD_ALL - }, - { - value: ResolutionStrategy.PUBLISH_ALL } ] as const; diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx index 81b3bc51d5..a114567cec 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx @@ -94,6 +94,7 @@ const SyncWorkspaceDialog: React.FC = (props) => { const handleRetry = React.useCallback(() => { props.retry(); }, []); + switch (props.syncingState?.process.phase) { case SyncingPhase.START: return ( @@ -124,18 +125,21 @@ const SyncWorkspaceDialog: React.FC = (props) => { /> ); case SyncingPhase.RESOLVING: - return ( - - ); + ); + } + return null; case SyncingPhase.ERROR: case SyncingPhase.SUCCESS: return ( From be4c716896e06a989f8f7757fac2260f235845a6 Mon Sep 17 00:00:00 2001 From: pKallert Date: Thu, 20 Mar 2025 13:02:49 +0100 Subject: [PATCH 06/11] Fix: Undo changes to sync dialogue --- packages/neos-ui-sagas/src/Sync/index.ts | 2 ++ .../SyncWorkspaceDialog.tsx | 25 ++++++++----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/neos-ui-sagas/src/Sync/index.ts b/packages/neos-ui-sagas/src/Sync/index.ts index 3d5677a206..ff4819d5a5 100644 --- a/packages/neos-ui-sagas/src/Sync/index.ts +++ b/packages/neos-ui-sagas/src/Sync/index.ts @@ -124,6 +124,8 @@ export const makeResolveConflicts = (deps: { yield * discardAll(); return false; // don't continue publishing as this is a deletes all } + + continue; } } diff --git a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx index a114567cec..6b3ea714d7 100644 --- a/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/SyncWorkspaceDialog/SyncWorkspaceDialog.tsx @@ -125,21 +125,18 @@ const SyncWorkspaceDialog: React.FC = (props) => { /> ); case SyncingPhase.RESOLVING: - if (props.syncingState.process.strategy === ResolutionStrategy.FORCE) { - return ( - - ); - } - return null; + ); case SyncingPhase.ERROR: case SyncingPhase.SUCCESS: return ( From 8893756aa653a1739d8c7b5efc71144f1f416dd5 Mon Sep 17 00:00:00 2001 From: pKallert Date: Fri, 21 Mar 2025 11:07:33 +0100 Subject: [PATCH 07/11] Adjust publishing dialog to use partial publish error --- .../Translations/en/PublishingDialog.xlf | 6 ++-- .../src/CR/Publishing/index.ts | 31 +++++++++++++++++++ packages/neos-ui-sagas/src/Publish/index.ts | 10 ++++-- .../PublishingDialog/ConfirmationDialog.tsx | 12 ++++--- .../PublishingDialog/PublishingDialog.tsx | 27 ++++++++++++++-- 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/Resources/Private/Translations/en/PublishingDialog.xlf b/Resources/Private/Translations/en/PublishingDialog.xlf index 7ca6fab54b..7ba76e783d 100644 --- a/Resources/Private/Translations/en/PublishingDialog.xlf +++ b/Resources/Private/Translations/en/PublishingDialog.xlf @@ -75,16 +75,16 @@ OK - Publish all changes in document "{scopeTitle}" + Could not publish changes to document "{scopeTitle}" - Are you sure that you want to publish all {numberOfChanges} change(s) in document "{scopeTitle}" from workspace "{sourceWorkspaceName}" to workspace "{targetWorkspaceName}"? Be careful: This cannot be undone! + Do you want to instead publish {numberOfChanges} change(s) in to workspace "{targetWorkspaceName}"? Be careful: This cannot be undone! No, cancel - Yes, publish + Yes, publish all changes in site instead Publishing all changes in document "{scopeTitle}"... diff --git a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts index 52385f4b71..be98d0919e 100644 --- a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts @@ -26,6 +26,7 @@ export enum PublishingPhase { START, ONGOING, CONFLICTS, + PARTIAL_PUBLISH_CONFLICTS, SUCCESS, ERROR } @@ -40,6 +41,7 @@ export type State = null | { autoConfirmed: boolean } | { phase: PublishingPhase.CONFLICTS } + | { phase: PublishingPhase.PARTIAL_PUBLISH_CONFLICTS } | { phase: PublishingPhase.ERROR; error: null | AnyError; @@ -58,6 +60,8 @@ export enum actionTypes { CONFIRMED = '@neos/neos-ui/CR/Publishing/CONFIRMED', CONFLICTS_OCCURRED = '@neos/neos-ui/CR/Publishing/CONFLICTS_OCCURRED', CONFLICTS_RESOLVED = '@neos/neos-ui/CR/Publishing/CONFLICTS_RESOLVED', + PARTIAL_PUBLISH_CONFLICTS_OCCURRED = '@neos/neos-ui/CR/Publishing/PARTIAL_PUBLISH_CONFLICTS_OCCURRED', + PARTIAL_PUBLISH_CONFLICTS_RESOLVED = '@neos/neos-ui/CR/Publishing/PARTIAL_PUBLISH_CONFLICTS_RESOLVED', FAILED = '@neos/neos-ui/CR/Publishing/FAILED', RETRIED = '@neos/neos-ui/CR/Publishing/RETRIED', SUCEEDED = '@neos/neos-ui/CR/Publishing/SUCEEDED', @@ -91,6 +95,16 @@ const conflicts = () => createAction(actionTypes.CONFLICTS_OCCURRED); */ const resolveConflicts = () => createAction(actionTypes.CONFLICTS_RESOLVED); +/** + * Signal that partial publish conflict has occurred during the publish/discard operation + */ +const partialPublishConflict = () => createAction(actionTypes.PARTIAL_PUBLISH_CONFLICTS_OCCURRED); + +/** + * Signal that partial publish conflict has been resolved during the publish/discard operation + */ +const resolvePartialPublishConflict = () => createAction(actionTypes.PARTIAL_PUBLISH_CONFLICTS_RESOLVED); + /** * Signal that the ongoing publish/discard workflow has failed */ @@ -127,6 +141,8 @@ export const actions = { confirm, conflicts, resolveConflicts, + partialPublishConflict, + resolvePartialPublishConflict, fail, retry, succeed, @@ -191,6 +207,21 @@ export const reducer = (state: State = defaultState, action: Action): State => { autoConfirmed: false } }; + case actionTypes.PARTIAL_PUBLISH_CONFLICTS_OCCURRED: + return { + ...state, + process: { + phase: PublishingPhase.PARTIAL_PUBLISH_CONFLICTS + } + }; + case actionTypes.PARTIAL_PUBLISH_CONFLICTS_RESOLVED: + return { + ...state, + process: { + phase: PublishingPhase.ONGOING, + autoConfirmed: false + } + }; case actionTypes.FAILED: return { ...state, diff --git a/packages/neos-ui-sagas/src/Publish/index.ts b/packages/neos-ui-sagas/src/Publish/index.ts index b3720f1612..ca5be28012 100644 --- a/packages/neos-ui-sagas/src/Publish/index.ts +++ b/packages/neos-ui-sagas/src/Publish/index.ts @@ -51,6 +51,7 @@ const PUBLISH_SUCCESS_TRANSLATIONS = { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.success.message', fallback: '{numberOfChanges} change(s) in document "{scopeTitle}" were sucessfully published to workspace "{targetWorkspaceName}".' } + } export function * watchPublishing({routes}: {routes: Routes}) { @@ -143,10 +144,13 @@ export function * watchPublishing({routes}: {routes: Routes}) { yield put(actions.CR.Publishing.finish()); } yield * reloadAfterPublishing(); - } else if ('conflicts' in result) { + } else if ('conflicts' in result && result.isPartialPublish) { + console.log('partial publish'); + yield put(actions.CR.Publishing.partialPublishConflict()); + } else if ('conflicts' in result && !result.isPartialPublish) { yield put(actions.CR.Publishing.conflicts()); - const conflictsWereResolved: boolean = - yield * resolveConflicts(result.conflicts); + + const conflictsWereResolved = yield * resolveConflicts(result.conflicts); if (conflictsWereResolved) { yield put(actions.CR.Publishing.resolveConflicts()); diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx index 49e3e3e03b..ad9bd7f910 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx @@ -69,18 +69,19 @@ const ConfirmationDialogVariants = { } } }, - // NOTE that with https://github.com/neos/neos-ui/pull/3909 this variant is currently effectively not used as confirmation is not required + // NOTE that with https://github.com/neos/neos-ui/pull/3909 this variant is currently effectively not used. + // If there is a partial publish error, this confirmation dialog is now shown instead [PublishingScope.DOCUMENT]: { label: { title: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.title', fallback: (props: { scopeTitle: string; }) => - `Publish all changes in document "${props.scopeTitle}"` + `Could not publish changes to document "${props.scopeTitle}"` }, message: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.message', - fallback: (props: { numberOfChanges: number; scopeTitle: string; sourceWorkspaceName: string; targetWorkspaceName: null | string; }) => - `Are you sure that you want to publish all ${props.numberOfChanges} change(s) in document "${props.scopeTitle}" from workspace "${props.sourceWorkspaceName}" to workspace "${props.targetWorkspaceName}"? Be careful: This cannot be undone!` + fallback: (props: { numberOfSiteChanges: number; scopeTitle: string; sourceWorkspaceName: string; targetWorkspaceName: null | string; }) => + `Do you want to instead publish ${props.numberOfSiteChanges} change(s) in to workspace "${props.targetWorkspaceName}"? Be careful: This cannot be undone!` }, cancel: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.cancel', @@ -88,7 +89,7 @@ const ConfirmationDialogVariants = { }, confirm: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.confirm', - fallback: 'Yes, publish' + fallback: 'Yes, publish all changes in site instead' } } } @@ -176,6 +177,7 @@ type ConfirmationDialogProps = { sourceWorkspaceName: string; targetWorkspaceName: null | string; numberOfChanges: number; + numberOfSiteChanges: null | number; onAbort: () => void; onConfirm: () => void; } diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx index a5e8fe6c91..964bd5eb43 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx @@ -40,18 +40,19 @@ type PublishingDialogProperties = sourceWorkspaceName: string; targetWorkspaceName: null | string; numberOfChanges: number; + numberOfSiteChanges: null | number; }; type PublishingDialogHandlers = { cancel: () => void; confirm: () => void; + start: (mode: PublishingMode, scope: PublishingScope, requireConfirmation: boolean) => void; retry: () => void; acknowledge: () => void; } type PublishingDialogProps = PublishingDialogProperties & PublishingDialogHandlers; - const PublishingDialog: React.FC = (props) => { const handleCancel = React.useCallback(() => { props.cancel(); @@ -65,6 +66,9 @@ const PublishingDialog: React.FC = (props) => { const handleAcknowledge = React.useCallback(() => { props.acknowledge(); }, []); + const handleStart = React.useCallback(() => { + props.start(PublishingMode.PUBLISH, PublishingScope.SITE, true); + }, []); if (props.publishingState === null) { return null; @@ -80,6 +84,7 @@ const PublishingDialog: React.FC = (props) => { sourceWorkspaceName={props.sourceWorkspaceName} targetWorkspaceName={props.targetWorkspaceName} numberOfChanges={props.numberOfChanges} + numberOfSiteChanges={props.numberOfSiteChanges} onAbort={handleCancel} onConfirm={handleConfirm} /> @@ -102,7 +107,21 @@ const PublishingDialog: React.FC = (props) => { case PublishingPhase.CONFLICTS: return null; - + case PublishingPhase.PARTIAL_PUBLISH_CONFLICTS: + console.log('publishing phase') + return ( + + ); case PublishingPhase.ERROR: case PublishingPhase.SUCCESS: return ( @@ -160,6 +179,8 @@ export default connect((state: GlobalState): PublishingDialogProperties => { numberOfChanges = publishableNodesInDocumentSelector(state).length; } + const numberOfSiteChanges = publishableNodesSelector(state).length; + let scopeTitle = 'N/A'; if (scope === PublishingScope.ALL) { scopeTitle = sourceWorkspaceName; @@ -174,10 +195,12 @@ export default connect((state: GlobalState): PublishingDialogProperties => { sourceWorkspaceName, targetWorkspaceName, numberOfChanges, + numberOfSiteChanges, scopeTitle }; }, { confirm: (actions as any).CR.Publishing.confirm, + start: (actions as any).CR.Publishing.start, cancel: (actions as any).CR.Publishing.cancel, retry: (actions as any).CR.Publishing.retry, acknowledge: (actions as any).CR.Publishing.acknowledge From 4185acf939eaf5539d0eb753fa8698e3334e83c5 Mon Sep 17 00:00:00 2001 From: pKallert Date: Fri, 21 Mar 2025 12:42:12 +0100 Subject: [PATCH 08/11] Fix: Move PublishAll Dialog to separate dialog --- .../Translations/en/PublishingDialog.xlf | 19 ++- .../src/CR/Publishing/index.ts | 15 --- packages/neos-ui-sagas/src/Publish/index.ts | 4 +- .../PublishingDialog/ConfirmationDialog.tsx | 12 +- .../Modals/PublishingDialog/Diagram.tsx | 16 +++ .../PublishingDialog/PublishAllDialog.tsx | 120 ++++++++++++++++++ .../PublishingDialog/PublishingDialog.tsx | 6 +- .../Modals/PublishingDialog/style.module.css | 4 + 8 files changed, 166 insertions(+), 30 deletions(-) create mode 100644 packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllDialog.tsx diff --git a/Resources/Private/Translations/en/PublishingDialog.xlf b/Resources/Private/Translations/en/PublishingDialog.xlf index 7ba76e783d..f5f6560509 100644 --- a/Resources/Private/Translations/en/PublishingDialog.xlf +++ b/Resources/Private/Translations/en/PublishingDialog.xlf @@ -75,16 +75,16 @@ OK - Could not publish changes to document "{scopeTitle}" + Publish all changes in document "{scopeTitle}" - Do you want to instead publish {numberOfChanges} change(s) in to workspace "{targetWorkspaceName}"? Be careful: This cannot be undone! + Are you sure that you want to publish all {numberOfChanges} change(s) in document "{scopeTitle}" from workspace "{sourceWorkspaceName}" to workspace "{targetWorkspaceName}"? Be careful: This cannot be undone! No, cancel - Yes, publish all changes in site instead + Yes, publish Publishing all changes in document "{scopeTitle}"... @@ -110,6 +110,19 @@ OK + + Could not publish changes in document "{scopeTitle}" + + + There seem to be dependencies to other documents. + Do you want to instead publish all changes in site to workspace "{targetWorkspaceName}"? Be careful: This cannot be undone! + + + No, cancel + + + Yes, publish all changes in site + Discard all changes in workspace "{scopeTitle}" diff --git a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts index be98d0919e..59fe7ddc8b 100644 --- a/packages/neos-ui-redux-store/src/CR/Publishing/index.ts +++ b/packages/neos-ui-redux-store/src/CR/Publishing/index.ts @@ -61,7 +61,6 @@ export enum actionTypes { CONFLICTS_OCCURRED = '@neos/neos-ui/CR/Publishing/CONFLICTS_OCCURRED', CONFLICTS_RESOLVED = '@neos/neos-ui/CR/Publishing/CONFLICTS_RESOLVED', PARTIAL_PUBLISH_CONFLICTS_OCCURRED = '@neos/neos-ui/CR/Publishing/PARTIAL_PUBLISH_CONFLICTS_OCCURRED', - PARTIAL_PUBLISH_CONFLICTS_RESOLVED = '@neos/neos-ui/CR/Publishing/PARTIAL_PUBLISH_CONFLICTS_RESOLVED', FAILED = '@neos/neos-ui/CR/Publishing/FAILED', RETRIED = '@neos/neos-ui/CR/Publishing/RETRIED', SUCEEDED = '@neos/neos-ui/CR/Publishing/SUCEEDED', @@ -100,11 +99,6 @@ const resolveConflicts = () => createAction(actionTypes.CONFLICTS_RESOLVED); */ const partialPublishConflict = () => createAction(actionTypes.PARTIAL_PUBLISH_CONFLICTS_OCCURRED); -/** - * Signal that partial publish conflict has been resolved during the publish/discard operation - */ -const resolvePartialPublishConflict = () => createAction(actionTypes.PARTIAL_PUBLISH_CONFLICTS_RESOLVED); - /** * Signal that the ongoing publish/discard workflow has failed */ @@ -142,7 +136,6 @@ export const actions = { conflicts, resolveConflicts, partialPublishConflict, - resolvePartialPublishConflict, fail, retry, succeed, @@ -214,14 +207,6 @@ export const reducer = (state: State = defaultState, action: Action): State => { phase: PublishingPhase.PARTIAL_PUBLISH_CONFLICTS } }; - case actionTypes.PARTIAL_PUBLISH_CONFLICTS_RESOLVED: - return { - ...state, - process: { - phase: PublishingPhase.ONGOING, - autoConfirmed: false - } - }; case actionTypes.FAILED: return { ...state, diff --git a/packages/neos-ui-sagas/src/Publish/index.ts b/packages/neos-ui-sagas/src/Publish/index.ts index ca5be28012..381c054182 100644 --- a/packages/neos-ui-sagas/src/Publish/index.ts +++ b/packages/neos-ui-sagas/src/Publish/index.ts @@ -145,12 +145,12 @@ export function * watchPublishing({routes}: {routes: Routes}) { } yield * reloadAfterPublishing(); } else if ('conflicts' in result && result.isPartialPublish) { - console.log('partial publish'); yield put(actions.CR.Publishing.partialPublishConflict()); } else if ('conflicts' in result && !result.isPartialPublish) { yield put(actions.CR.Publishing.conflicts()); - const conflictsWereResolved = yield * resolveConflicts(result.conflicts); + const conflictsWereResolved: boolean = + yield * resolveConflicts(result.conflicts); if (conflictsWereResolved) { yield put(actions.CR.Publishing.resolveConflicts()); diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx index ad9bd7f910..49e3e3e03b 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/ConfirmationDialog.tsx @@ -69,19 +69,18 @@ const ConfirmationDialogVariants = { } } }, - // NOTE that with https://github.com/neos/neos-ui/pull/3909 this variant is currently effectively not used. - // If there is a partial publish error, this confirmation dialog is now shown instead + // NOTE that with https://github.com/neos/neos-ui/pull/3909 this variant is currently effectively not used as confirmation is not required [PublishingScope.DOCUMENT]: { label: { title: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.title', fallback: (props: { scopeTitle: string; }) => - `Could not publish changes to document "${props.scopeTitle}"` + `Publish all changes in document "${props.scopeTitle}"` }, message: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.message', - fallback: (props: { numberOfSiteChanges: number; scopeTitle: string; sourceWorkspaceName: string; targetWorkspaceName: null | string; }) => - `Do you want to instead publish ${props.numberOfSiteChanges} change(s) in to workspace "${props.targetWorkspaceName}"? Be careful: This cannot be undone!` + fallback: (props: { numberOfChanges: number; scopeTitle: string; sourceWorkspaceName: string; targetWorkspaceName: null | string; }) => + `Are you sure that you want to publish all ${props.numberOfChanges} change(s) in document "${props.scopeTitle}" from workspace "${props.sourceWorkspaceName}" to workspace "${props.targetWorkspaceName}"? Be careful: This cannot be undone!` }, cancel: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.cancel', @@ -89,7 +88,7 @@ const ConfirmationDialogVariants = { }, confirm: { id: 'Neos.Neos.Ui:PublishingDialog:publish.document.confirmation.confirm', - fallback: 'Yes, publish all changes in site instead' + fallback: 'Yes, publish' } } } @@ -177,7 +176,6 @@ type ConfirmationDialogProps = { sourceWorkspaceName: string; targetWorkspaceName: null | string; numberOfChanges: number; - numberOfSiteChanges: null | number; onAbort: () => void; onConfirm: () => void; } diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/Diagram.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/Diagram.tsx index 844ac68991..951c39fbe8 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/Diagram.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/Diagram.tsx @@ -91,6 +91,22 @@ const Changes: React.FC<{ /> ); } + if (props.phase === PublishingPhase.PARTIAL_PUBLISH_CONFLICTS) { + return ( +
+ + + {props.numberOfChanges} + +
+ ); + } if (props.phase === PublishingPhase.SUCCESS) { return ( diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllDialog.tsx new file mode 100644 index 0000000000..4051d8f3a7 --- /dev/null +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishAllDialog.tsx @@ -0,0 +1,120 @@ +/* + * This file is part of the Neos.Neos.Ui package. + * + * (c) Contributors of the Neos Project - www.neos.io + * + * This package is Open Source Software. For the full copyright and license + * information, please view the LICENSE file which was distributed with this + * source code. + */ +import React from 'react'; + +import {Button, Dialog, Icon} from '@neos-project/react-ui-components'; +import I18n from '@neos-project/neos-ui-i18n'; +import {PublishingMode, PublishingPhase, PublishingScope} from '@neos-project/neos-ui-redux-store/src/CR/Publishing'; + +import {Diagram} from './Diagram'; + +import style from './style.module.css'; + +const PublishAllDialogVariants = { + id: 'neos-PublishAllDialog', + style: 'warn', + icon: { + title: 'share-square-o', + confirm: 'share-square-o' + }, + label: { + title: { + id: 'Neos.Neos.Ui:PublishingDialog:publishAll.document.confirmation.title', + fallback: (props: { scopeTitle: string; }) => + `Could not publish changes in document "${props.scopeTitle}"` + }, + message: { + id: 'Neos.Neos.Ui:PublishingDialog:publishAll.document.confirmation.message', + fallback: (props: { scopeTitle: string; sourceWorkspaceName: string; targetWorkspaceName: null | string; }) => + `There seem to be dependencies to other documents. + Do you want to instead publish all changes in site to workspace "${props.targetWorkspaceName}"? Be careful: This cannot be undone!` + }, + cancel: { + id: 'Neos.Neos.Ui:PublishingDialog:publishAll.document.confirmation.cancel', + fallback: 'No, cancel' + }, + confirm: { + id: 'Neos.Neos.Ui:PublishingDialog:publishAll.document.confirmation.confirm', + fallback: 'Yes, publish all changes in site' + } + } +} as const; + +type PublishAllDialogProps = { + mode: PublishingMode; + scope: PublishingScope; + scopeTitle: string; + sourceWorkspaceName: string; + targetWorkspaceName: null | string; + numberOfChanges: number; + numberOfSiteChanges: number; + onAbort: () => void; + onConfirm: () => void; +} + +export const PublishAllDialog: React.FC = (props) => { + const variant = PublishAllDialogVariants; + + return ( + + + , + + ]} + title={
+ + + + +
} + onRequestClose={props.onAbort} + type={variant.style} + isOpen + autoFocus + theme={undefined as any} + style={undefined as any} + > +
+ + +
+
+ ); +}; diff --git a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx index 964bd5eb43..76cce8a685 100644 --- a/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx +++ b/packages/neos-ui/src/Containers/Modals/PublishingDialog/PublishingDialog.tsx @@ -23,6 +23,7 @@ import { import {ConfirmationDialog} from './ConfirmationDialog'; import {ProcessIndicator} from './ProcessIndicator'; import {ResultDialog} from './ResultDialog'; +import {PublishAllDialog} from './PublishAllDialog'; const { publishableNodesSelector, @@ -40,7 +41,7 @@ type PublishingDialogProperties = sourceWorkspaceName: string; targetWorkspaceName: null | string; numberOfChanges: number; - numberOfSiteChanges: null | number; + numberOfSiteChanges: number; }; type PublishingDialogHandlers = { @@ -84,7 +85,6 @@ const PublishingDialog: React.FC = (props) => { sourceWorkspaceName={props.sourceWorkspaceName} targetWorkspaceName={props.targetWorkspaceName} numberOfChanges={props.numberOfChanges} - numberOfSiteChanges={props.numberOfSiteChanges} onAbort={handleCancel} onConfirm={handleConfirm} /> @@ -110,7 +110,7 @@ const PublishingDialog: React.FC = (props) => { case PublishingPhase.PARTIAL_PUBLISH_CONFLICTS: console.log('publishing phase') return ( - Date: Fri, 21 Mar 2025 12:46:56 +0100 Subject: [PATCH 09/11] Feature: remove unused translations --- .../Translations/en/PublishingDialog.xlf | 9 --------- .../Translations/en/SyncWorkspaceDialog.xlf | 20 ------------------- 2 files changed, 29 deletions(-) diff --git a/Resources/Private/Translations/en/PublishingDialog.xlf b/Resources/Private/Translations/en/PublishingDialog.xlf index f5f6560509..8dc0e664d0 100644 --- a/Resources/Private/Translations/en/PublishingDialog.xlf +++ b/Resources/Private/Translations/en/PublishingDialog.xlf @@ -231,15 +231,6 @@ OK - - Could not publish all changes in "{scopeTitle}" - - - Some changes in this document are dependant on changes in other documents. Do you want to publish all changes to the workspace "{targetWorkspaceName}"? - - - Yes, publish all changes - diff --git a/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf b/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf index 466939575f..510206d11b 100644 --- a/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf +++ b/Resources/Private/Translations/en/SyncWorkspaceDialog.xlf @@ -44,12 +44,6 @@ This will discard all changes in your workspace, including those on other sites. - - Publish all changes to workspace "{workspaceName}" - - - This will publish all changes in your workspace, including those on other sites. - Cancel Synchronization @@ -64,26 +58,12 @@ Do you wish to proceed? Be careful: This cannot be undone!
- - Publish all changes in workspace "{workspaceName}" - - - You are about to publish all changes in workspace "{workspaceName}". This includes all changes on other sites. - - Do you wish to proceed? Be careful: This cannot be undone! - No, cancel Yes, discard everything - - No, cancel - - - Yes, publish everything - You are about to drop the following changes: From 326669a8551088e16f1ffc8749da73e9301c62e5 Mon Sep 17 00:00:00 2001 From: pKallert Date: Fri, 21 Mar 2025 13:04:02 +0100 Subject: [PATCH 10/11] Fix: linter --- .../PublishChangesInDocumentCommandHandler.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php index 78ef6d12cc..be4617ef35 100644 --- a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php +++ b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php @@ -52,8 +52,7 @@ final class PublishChangesInDocumentCommandHandler */ public function handle( PublishChangesInDocumentCommand $command - ): PublishSucceeded|ConflictsOccurred|PartialPublishFailed - { + ): PublishSucceeded|ConflictsOccurred { try { $publishingResult = $this->workspacePublishingService->publishChangesInDocument( $command->contentRepositoryId, From 73ad5136ca57b83f700c1d34bde78689ed94e48b Mon Sep 17 00:00:00 2001 From: pKallert Date: Fri, 21 Mar 2025 13:06:08 +0100 Subject: [PATCH 11/11] Fix: linter --- .../PublishChangesInDocumentCommandHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php index be4617ef35..13def4119e 100644 --- a/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php +++ b/Classes/Application/PublishChangesInDocument/PublishChangesInDocumentCommandHandler.php @@ -106,7 +106,6 @@ public function handle( 1705053432, $e ); - } } }