From 288178c44e4424e05fad5d7ac843ee65cdeebce2 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Thu, 12 Mar 2026 09:38:41 +0000 Subject: [PATCH] implements PR-07d asset mutation and structural sync orchestration --- ...dioAssetsStructuralSyncRequestedEvent.java | 16 ++++++++ .../workspaces/assets/AssetWorkspace.java | 38 +++++++++++++------ .../AssetWorkspaceMutationUpdatePlanner.java | 15 ++++++++ .../AssetWorkspaceMutationUpdateStrategy.java | 6 +++ ...setWorkspaceMutationUpdatePlannerTest.java | 20 ++++++++++ 5 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 prometeu-studio/src/main/java/p/studio/events/StudioAssetsStructuralSyncRequestedEvent.java create mode 100644 prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlanner.java create mode 100644 prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdateStrategy.java create mode 100644 prometeu-studio/src/test/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlannerTest.java diff --git a/prometeu-studio/src/main/java/p/studio/events/StudioAssetsStructuralSyncRequestedEvent.java b/prometeu-studio/src/main/java/p/studio/events/StudioAssetsStructuralSyncRequestedEvent.java new file mode 100644 index 00000000..72f96bba --- /dev/null +++ b/prometeu-studio/src/main/java/p/studio/events/StudioAssetsStructuralSyncRequestedEvent.java @@ -0,0 +1,16 @@ +package p.studio.events; + +import p.studio.projects.ProjectReference; +import p.studio.workspaces.assets.AssetWorkspaceSelectionKey; + +import java.util.Objects; + +public record StudioAssetsStructuralSyncRequestedEvent( + ProjectReference project, + AssetWorkspaceSelectionKey preferredSelectionKey, + String reason) implements StudioEvent { + public StudioAssetsStructuralSyncRequestedEvent { + Objects.requireNonNull(project, "project"); + Objects.requireNonNull(reason, "reason"); + } +} diff --git a/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java index 91156bc7..66784a60 100644 --- a/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java +++ b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspace.java @@ -155,6 +155,12 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio applyAssetSummaryPatch(event.summary()); } }); + workspaceBus.subscribe(StudioAssetsStructuralSyncRequestedEvent.class, event -> { + if (projectMatches(event.project())) { + pendingSelectionKey = event.preferredSelectionKey(); + refresh(); + } + }); } private boolean projectMatches(ProjectReference project) { @@ -313,9 +319,8 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio } AssetCreationWizard.showAndWait(root.getScene().getWindow(), projectReference, assetCreationService) .ifPresent(result -> { - pendingSelectionKey = result.selectionKey(); appendLog("Asset created: " + projectRelativePath(result.assetRoot()) + "."); - refresh(); + requestStructuralSync("asset created", result.selectionKey()); }); } @@ -680,8 +685,10 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio mutationService.apply(projectReference, preview); appendLog("Applied " + actionLabel(preview.action()) + "."); stagedMutationPreview = null; - if (!applyMutationSummaryPatch(preview)) { - refresh(); + if (AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(preview.action()) == AssetWorkspaceMutationUpdateStrategy.LOCAL_PATCH) { + applyMutationSummaryPatch(preview); + } else { + requestStructuralSync("mutation applied: " + preview.action().name().toLowerCase(Locale.ROOT), null); } } catch (RuntimeException runtimeException) { final String message = rootCauseMessage(runtimeException); @@ -700,7 +707,7 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio .ifPresent(preview -> { appendLog("Applied " + actionLabel(preview.action()) + "."); stagedMutationPreview = null; - refresh(); + requestStructuralSync("mutation applied: " + preview.action().name().toLowerCase(Locale.ROOT), null); }); } @@ -713,8 +720,10 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio mutationService.apply(projectReference, preview); appendLog("Applied " + actionLabel(preview.action()) + "."); stagedMutationPreview = null; - if (!applyMutationSummaryPatch(preview)) { - refresh(); + if (AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(preview.action()) == AssetWorkspaceMutationUpdateStrategy.LOCAL_PATCH) { + applyMutationSummaryPatch(preview); + } else { + requestStructuralSync("mutation applied: " + preview.action().name().toLowerCase(Locale.ROOT), null); } } catch (RuntimeException runtimeException) { final String message = rootCauseMessage(runtimeException); @@ -725,17 +734,16 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio } } - private boolean applyMutationSummaryPatch(AssetWorkspaceMutationPreview preview) { + private void applyMutationSummaryPatch(AssetWorkspaceMutationPreview preview) { final AssetWorkspaceAssetSummary updatedSummary = switch (preview.action()) { case INCLUDE_IN_BUILD -> withBuildParticipation(preview.asset(), AssetWorkspaceBuildParticipation.INCLUDED); case EXCLUDE_FROM_BUILD -> withBuildParticipation(preview.asset(), AssetWorkspaceBuildParticipation.EXCLUDED); default -> null; }; if (updatedSummary == null) { - return false; + return; } workspaceBus.publish(new StudioAssetsAssetSummaryPatchedEvent(projectReference, updatedSummary)); - return true; } private Node createStagedMutationPanel(AssetWorkspaceMutationPreview preview) { @@ -886,7 +894,11 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio mutationService.apply(projectReference, preview); appendLog("Applied " + actionLabel(preview.action()) + "."); stagedMutationPreview = null; - refresh(); + if (AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(preview.action()) == AssetWorkspaceMutationUpdateStrategy.LOCAL_PATCH) { + applyMutationSummaryPatch(preview); + } else { + requestStructuralSync("mutation applied: " + preview.action().name().toLowerCase(Locale.ROOT), null); + } } catch (RuntimeException runtimeException) { final String message = rootCauseMessage(runtimeException); appendLog("Mutation failed: " + message); @@ -895,6 +907,10 @@ public final class AssetWorkspace implements Workspace, AssetWorkspaceInteractio } } + private void requestStructuralSync(String reason, AssetWorkspaceSelectionKey preferredSelectionKey) { + workspaceBus.publish(new StudioAssetsStructuralSyncRequestedEvent(projectReference, preferredSelectionKey, reason)); + } + private Path firstPreviewInput(AssetWorkspaceAssetDetails details) { return details.inputsByRole().values().stream() .flatMap(List::stream) diff --git a/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlanner.java b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlanner.java new file mode 100644 index 00000000..877cf70c --- /dev/null +++ b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlanner.java @@ -0,0 +1,15 @@ +package p.studio.workspaces.assets; + +import java.util.Objects; + +public final class AssetWorkspaceMutationUpdatePlanner { + private AssetWorkspaceMutationUpdatePlanner() { + } + + public static AssetWorkspaceMutationUpdateStrategy forSuccessfulAction(AssetWorkspaceAction action) { + return switch (Objects.requireNonNull(action, "action")) { + case INCLUDE_IN_BUILD, EXCLUDE_FROM_BUILD -> AssetWorkspaceMutationUpdateStrategy.LOCAL_PATCH; + case REGISTER, RELOCATE, REMOVE -> AssetWorkspaceMutationUpdateStrategy.STRUCTURAL_SYNC; + }; + } +} diff --git a/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdateStrategy.java b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdateStrategy.java new file mode 100644 index 00000000..bacbffba --- /dev/null +++ b/prometeu-studio/src/main/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdateStrategy.java @@ -0,0 +1,6 @@ +package p.studio.workspaces.assets; + +public enum AssetWorkspaceMutationUpdateStrategy { + LOCAL_PATCH, + STRUCTURAL_SYNC +} diff --git a/prometeu-studio/src/test/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlannerTest.java b/prometeu-studio/src/test/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlannerTest.java new file mode 100644 index 00000000..ffda3e88 --- /dev/null +++ b/prometeu-studio/src/test/java/p/studio/workspaces/assets/AssetWorkspaceMutationUpdatePlannerTest.java @@ -0,0 +1,20 @@ +package p.studio.workspaces.assets; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +final class AssetWorkspaceMutationUpdatePlannerTest { + @Test + void classifiesLocalPatchMutations() { + assertEquals(AssetWorkspaceMutationUpdateStrategy.LOCAL_PATCH, AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(AssetWorkspaceAction.INCLUDE_IN_BUILD)); + assertEquals(AssetWorkspaceMutationUpdateStrategy.LOCAL_PATCH, AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(AssetWorkspaceAction.EXCLUDE_FROM_BUILD)); + } + + @Test + void classifiesStructuralSyncMutations() { + assertEquals(AssetWorkspaceMutationUpdateStrategy.STRUCTURAL_SYNC, AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(AssetWorkspaceAction.REGISTER)); + assertEquals(AssetWorkspaceMutationUpdateStrategy.STRUCTURAL_SYNC, AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(AssetWorkspaceAction.RELOCATE)); + assertEquals(AssetWorkspaceMutationUpdateStrategy.STRUCTURAL_SYNC, AssetWorkspaceMutationUpdatePlanner.forSuccessfulAction(AssetWorkspaceAction.REMOVE)); + } +}