From 66375aaa860c81bb9b625663be56238e790865bc Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Fri, 20 Mar 2026 04:57:42 +0000 Subject: [PATCH] packer (WIP) --- .../java/p/studio/utilities/i18n/I18n.java | 36 ++ .../workspaces/assets/AssetWorkspace.java | 9 + .../assets/wizards/PackWorkspaceWizard.java | 437 ++++++++++++++++++ .../main/resources/i18n/messages.properties | 36 ++ 4 files changed, 518 insertions(+) create mode 100644 prometeu-studio/src/main/java/p/studio/workspaces/assets/wizards/PackWorkspaceWizard.java diff --git a/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java b/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java index 21ce9acf..7ee6820e 100644 --- a/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java +++ b/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java @@ -249,6 +249,42 @@ public enum I18n { ASSETS_RELOCATE_WIZARD_ERROR_OUTSIDE_ASSETS("assets.relocateWizard.error.outsideAssets"), ASSETS_RELOCATE_WIZARD_ERROR_TARGET_ALREADY_ASSET("assets.relocateWizard.error.targetAlreadyAsset"), ASSETS_RELOCATE_WIZARD_ERROR_TARGET_SAME("assets.relocateWizard.error.targetSame"), + ASSETS_PACK_WIZARD_TITLE("assets.packWizard.title"), + ASSETS_PACK_WIZARD_STEP_SUMMARY_TITLE("assets.packWizard.step.summary.title"), + ASSETS_PACK_WIZARD_STEP_SUMMARY_DESCRIPTION("assets.packWizard.step.summary.description"), + ASSETS_PACK_WIZARD_STEP_VALIDATION_TITLE("assets.packWizard.step.validation.title"), + ASSETS_PACK_WIZARD_STEP_VALIDATION_DESCRIPTION("assets.packWizard.step.validation.description"), + ASSETS_PACK_WIZARD_STEP_PACKING_TITLE("assets.packWizard.step.packing.title"), + ASSETS_PACK_WIZARD_STEP_PACKING_DESCRIPTION("assets.packWizard.step.packing.description"), + ASSETS_PACK_WIZARD_STEP_RESULT_TITLE("assets.packWizard.step.result.title"), + ASSETS_PACK_WIZARD_STEP_RESULT_DESCRIPTION("assets.packWizard.step.result.description"), + ASSETS_PACK_WIZARD_BUTTON_VALIDATE("assets.packWizard.button.validate"), + ASSETS_PACK_WIZARD_BUTTON_PACK("assets.packWizard.button.pack"), + ASSETS_PACK_WIZARD_BUTTON_CLOSE("assets.packWizard.button.close"), + ASSETS_PACK_WIZARD_BUTTON_COPY_FAILURES("assets.packWizard.button.copyFailures"), + ASSETS_PACK_WIZARD_LOADING_SUMMARY("assets.packWizard.loading.summary"), + ASSETS_PACK_WIZARD_LOADING_VALIDATION("assets.packWizard.loading.validation"), + ASSETS_PACK_WIZARD_LOADING_PACKING("assets.packWizard.loading.packing"), + ASSETS_PACK_WIZARD_LABEL_CANONICAL_ARTIFACT("assets.packWizard.label.canonicalArtifact"), + ASSETS_PACK_WIZARD_LABEL_INCLUDED_ASSETS("assets.packWizard.label.includedAssets"), + ASSETS_PACK_WIZARD_LABEL_OUTSIDE_BUILD_SET("assets.packWizard.label.outsideBuildSet"), + ASSETS_PACK_WIZARD_LABEL_TOTAL_IN_SCOPE("assets.packWizard.label.totalInScope"), + ASSETS_PACK_WIZARD_LABEL_VALID_ASSETS("assets.packWizard.label.validAssets"), + ASSETS_PACK_WIZARD_LABEL_BLOCKED_ASSETS("assets.packWizard.label.blockedAssets"), + ASSETS_PACK_WIZARD_LABEL_STATUS("assets.packWizard.label.status"), + ASSETS_PACK_WIZARD_LABEL_PACKED_ASSETS("assets.packWizard.label.packedAssets"), + ASSETS_PACK_WIZARD_LABEL_ELAPSED("assets.packWizard.label.elapsed"), + ASSETS_PACK_WIZARD_LABEL_EMITTED_ARTIFACTS("assets.packWizard.label.emittedArtifacts"), + ASSETS_PACK_WIZARD_STATUS_READY("assets.packWizard.status.ready"), + ASSETS_PACK_WIZARD_STATUS_BLOCKED("assets.packWizard.status.blocked"), + ASSETS_PACK_WIZARD_STATUS_RUNNING("assets.packWizard.status.running"), + ASSETS_PACK_WIZARD_STATUS_FINISHED("assets.packWizard.status.finished"), + ASSETS_PACK_WIZARD_VALIDATION_EMPTY("assets.packWizard.validation.empty"), + ASSETS_PACK_WIZARD_RESULT_NO_ARTIFACTS("assets.packWizard.result.noArtifacts"), + ASSETS_PACK_WIZARD_RESULT_COPY_FAILURES_HINT("assets.packWizard.result.copyFailuresHint"), + ASSETS_PACK_WIZARD_ERROR_SUMMARY("assets.packWizard.error.summary"), + ASSETS_PACK_WIZARD_ERROR_VALIDATION("assets.packWizard.error.validation"), + ASSETS_PACK_WIZARD_ERROR_PACK("assets.packWizard.error.pack"), WORKSPACE_DEBUG("workspace.debug"), 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 89647c90..445111b6 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 @@ -18,6 +18,7 @@ import p.studio.workspaces.assets.list.AssetListControl; import p.studio.workspaces.assets.messages.events.StudioAssetsRefreshRequestedEvent; import p.studio.workspaces.assets.messages.events.StudioAssetsWorkspaceSelectionRequestedEvent; import p.studio.workspaces.assets.wizards.AddAssetWizard; +import p.studio.workspaces.assets.wizards.PackWorkspaceWizard; import java.util.List; @@ -121,6 +122,7 @@ public final class AssetWorkspace extends Workspace { "studio-button", "studio-button-secondary", "assets-workspace-action-button"); + packButton.setOnAction(event -> openPackWizard()); return packButton; } @@ -134,6 +136,13 @@ public final class AssetWorkspace extends Workspace { }); } + private void openPackWizard() { + if (root.getScene() == null) { + return; + } + PackWorkspaceWizard.showAndWait(root.getScene().getWindow(), projectReference); + } + private SplitPane createAssetSplitPane() { final var splitPane = new SplitPane(assetListControl, detailsControl); splitPane.setDividerPositions(0.34); diff --git a/prometeu-studio/src/main/java/p/studio/workspaces/assets/wizards/PackWorkspaceWizard.java b/prometeu-studio/src/main/java/p/studio/workspaces/assets/wizards/PackWorkspaceWizard.java new file mode 100644 index 00000000..2604d3f3 --- /dev/null +++ b/prometeu-studio/src/main/java/p/studio/workspaces/assets/wizards/PackWorkspaceWizard.java @@ -0,0 +1,437 @@ +package p.studio.workspaces.assets.wizards; + +import javafx.application.Platform; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.Window; +import p.packer.dtos.PackerEmittedArtifactDTO; +import p.packer.dtos.PackerPackValidationAssetDTO; +import p.packer.messages.PackWorkspaceRequest; +import p.packer.messages.PackWorkspaceResult; +import p.packer.messages.PackWorkspaceSummaryRequest; +import p.packer.messages.PackWorkspaceSummaryResult; +import p.packer.messages.PackerOperationStatus; +import p.packer.messages.ValidatePackWorkspaceRequest; +import p.packer.messages.ValidatePackWorkspaceResult; +import p.studio.Container; +import p.studio.projects.ProjectReference; +import p.studio.utilities.i18n.I18n; +import p.studio.workspaces.assets.details.AssetDetailsUiSupport; + +import java.util.List; +import java.util.Objects; + +public final class PackWorkspaceWizard { + private enum Phase { + SUMMARY, + VALIDATION, + PACKING, + RESULT + } + + private final ProjectReference projectReference; + private final Stage stage; + private final Label stepTitle = new Label(); + private final Label stepDescription = new Label(); + private final VBox stepBody = new VBox(12); + private final Label feedbackLabel = new Label(); + private final Button backButton = new Button(); + private final Button nextButton = new Button(); + private final Button packButton = new Button(); + private final Button closeButton = new Button(); + private final Button copyFailuresButton = new Button(); + + private Phase phase = Phase.SUMMARY; + private boolean loadingSummary; + private boolean loadingValidation; + private boolean packing; + + private PackWorkspaceSummaryResult summaryResult; + private ValidatePackWorkspaceResult validationResult; + private PackWorkspaceResult packResult; + + private PackWorkspaceWizard(Window owner, ProjectReference projectReference) { + this.projectReference = Objects.requireNonNull(projectReference, "projectReference"); + this.stage = new Stage(); + stage.initOwner(owner); + stage.initModality(Modality.WINDOW_MODAL); + stage.setTitle(Container.i18n().text(I18n.ASSETS_PACK_WIZARD_TITLE)); + stage.setScene(new Scene(buildRoot(), 760, 560)); + stage.getScene().getStylesheets().add(Container.theme().getDefaultTheme()); + stage.setOnCloseRequest(event -> { + if (packing) { + event.consume(); + } + }); + render(); + loadSummary(); + } + + public static void showAndWait(Window owner, ProjectReference projectReference) { + new PackWorkspaceWizard(owner, projectReference).stage.showAndWait(); + } + + private VBox buildRoot() { + stepTitle.getStyleClass().add("studio-launcher-section-title"); + stepDescription.getStyleClass().add("studio-launcher-subtitle"); + feedbackLabel.getStyleClass().add("studio-launcher-feedback"); + feedbackLabel.setWrapText(true); + + backButton.textProperty().bind(Container.i18n().bind(I18n.WIZARD_BACK)); + backButton.getStyleClass().addAll("studio-button", "studio-button-secondary"); + backButton.setOnAction(ignored -> goBack()); + + nextButton.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_BUTTON_VALIDATE)); + nextButton.getStyleClass().addAll("studio-button", "studio-button-primary"); + nextButton.setOnAction(ignored -> loadValidation()); + + packButton.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_BUTTON_PACK)); + packButton.getStyleClass().addAll("studio-button", "studio-button-primary"); + packButton.setOnAction(ignored -> startPack()); + + copyFailuresButton.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_BUTTON_COPY_FAILURES)); + copyFailuresButton.getStyleClass().addAll("studio-button", "studio-button-secondary"); + copyFailuresButton.setDisable(true); + + closeButton.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_BUTTON_CLOSE)); + closeButton.getStyleClass().addAll("studio-button", "studio-button-cancel"); + closeButton.setOnAction(ignored -> { + if (!packing) { + stage.close(); + } + }); + + final HBox actions = new HBox(12, backButton, nextButton, packButton, copyFailuresButton, closeButton); + actions.setAlignment(Pos.CENTER_RIGHT); + + final VBox root = new VBox(16, stepTitle, stepDescription, stepBody, feedbackLabel, actions); + root.setPadding(new Insets(24)); + VBox.setVgrow(stepBody, Priority.ALWAYS); + return root; + } + + private void render() { + final boolean busy = loadingSummary || loadingValidation || packing; + backButton.setDisable(busy || phase == Phase.SUMMARY); + + nextButton.setVisible(phase == Phase.SUMMARY); + nextButton.setManaged(phase == Phase.SUMMARY); + nextButton.setDisable(busy || summaryResult == null); + + packButton.setVisible(phase == Phase.VALIDATION); + packButton.setManaged(phase == Phase.VALIDATION); + packButton.setDisable(busy || validationResult == null || !validationResult.validation().canPack()); + + copyFailuresButton.setVisible(phase == Phase.RESULT); + copyFailuresButton.setManaged(phase == Phase.RESULT); + + switch (phase) { + case SUMMARY -> renderSummaryPhase(); + case VALIDATION -> renderValidationPhase(); + case PACKING -> renderPackingPhase(); + case RESULT -> renderResultPhase(); + } + } + + private void renderSummaryPhase() { + stepTitle.textProperty().unbind(); + stepDescription.textProperty().unbind(); + stepTitle.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_SUMMARY_TITLE)); + stepDescription.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_SUMMARY_DESCRIPTION)); + if (loadingSummary) { + stepBody.getChildren().setAll(createBusyBox(I18n.ASSETS_PACK_WIZARD_LOADING_SUMMARY)); + return; + } + if (summaryResult == null) { + stepBody.getChildren().setAll(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_ERROR_SUMMARY))); + return; + } + + stepBody.getChildren().setAll( + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_CANONICAL_ARTIFACT), + summaryResult.packSummary().canonicalArtifactName()), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_INCLUDED_ASSETS), + Integer.toString(summaryResult.packSummary().includedRegisteredAssetCount())), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_OUTSIDE_BUILD_SET), + Integer.toString(summaryResult.packSummary().outsideBuildSetAssetCount())), + AssetDetailsUiSupport.createSectionMessage(summaryResult.summary())); + } + + private void renderValidationPhase() { + stepTitle.textProperty().unbind(); + stepDescription.textProperty().unbind(); + stepTitle.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_VALIDATION_TITLE)); + stepDescription.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_VALIDATION_DESCRIPTION)); + if (loadingValidation) { + stepBody.getChildren().setAll(createBusyBox(I18n.ASSETS_PACK_WIZARD_LOADING_VALIDATION)); + return; + } + if (validationResult == null) { + stepBody.getChildren().setAll(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_ERROR_VALIDATION))); + return; + } + + final VBox content = new VBox(12); + content.getChildren().addAll( + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_TOTAL_IN_SCOPE), + Integer.toString(validationResult.validation().totalAssetsInScope())), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_VALID_ASSETS), + Integer.toString(validationResult.validation().validAssetCount())), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_BLOCKED_ASSETS), + Integer.toString(validationResult.validation().blockedAssetCount())), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_STATUS), + validationResult.validation().canPack() + ? Container.i18n().text(I18n.ASSETS_PACK_WIZARD_STATUS_READY) + : Container.i18n().text(I18n.ASSETS_PACK_WIZARD_STATUS_BLOCKED)), + AssetDetailsUiSupport.createSectionMessage(validationResult.summary())); + + if (validationResult.assets().isEmpty()) { + content.getChildren().add(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_VALIDATION_EMPTY))); + } else { + final Accordion accordion = new Accordion(); + for (PackerPackValidationAssetDTO asset : validationResult.assets()) { + accordion.getPanes().add(createValidationPane(asset)); + } + VBox.setVgrow(accordion, Priority.ALWAYS); + content.getChildren().add(accordion); + } + stepBody.getChildren().setAll(content); + } + + private TitledPane createValidationPane(PackerPackValidationAssetDTO asset) { + final VBox content = new VBox(8); + content.getChildren().addAll( + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_LABEL_NAME), + asset.asset().identity().assetName()), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_LABEL_LOCATION), + asset.asset().identity().assetRoot().toString()), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_STATUS), + asset.blocked() + ? Container.i18n().text(I18n.ASSETS_PACK_WIZARD_STATUS_BLOCKED) + : Container.i18n().text(I18n.ASSETS_PACK_WIZARD_STATUS_READY))); + + final List blockingDiagnostics = asset.diagnostics().stream() + .filter(p.packer.dtos.PackerDiagnosticDTO::blocking) + .toList(); + if (blockingDiagnostics.isEmpty()) { + content.getChildren().add(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_DIAGNOSTICS_EMPTY))); + } else { + blockingDiagnostics.forEach(diagnostic -> content.getChildren().add(AssetDetailsUiSupport.createSectionMessage( + diagnostic.severity().name() + ": " + diagnostic.message()))); + } + + final String title = asset.asset().identity().assetName() + (asset.blocked() ? " (blocked)" : " (ready)"); + final TitledPane pane = new TitledPane(title, content); + pane.setExpanded(false); + return pane; + } + + private void renderPackingPhase() { + stepTitle.textProperty().unbind(); + stepDescription.textProperty().unbind(); + stepTitle.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_PACKING_TITLE)); + stepDescription.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_PACKING_DESCRIPTION)); + stepBody.getChildren().setAll(createBusyBox(I18n.ASSETS_PACK_WIZARD_LOADING_PACKING)); + } + + private void renderResultPhase() { + stepTitle.textProperty().unbind(); + stepDescription.textProperty().unbind(); + stepTitle.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_RESULT_TITLE)); + stepDescription.textProperty().bind(Container.i18n().bind(I18n.ASSETS_PACK_WIZARD_STEP_RESULT_DESCRIPTION)); + if (packResult == null) { + stepBody.getChildren().setAll(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_ERROR_PACK))); + return; + } + + final VBox content = new VBox(12); + content.getChildren().addAll( + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_STATUS), + switch (packResult.status()) { + case SUCCESS, PARTIAL -> Container.i18n().text(I18n.ASSETS_PACK_WIZARD_STATUS_FINISHED); + case FAILED -> packResult.status().name(); + }), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_CANONICAL_ARTIFACT), + packResult.result().canonicalArtifactName()), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_PACKED_ASSETS), + Integer.toString(packResult.result().packedAssetCount())), + AssetDetailsUiSupport.createKeyValueRow( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_ELAPSED), + formatElapsed(packResult.result().elapsedMillis())), + AssetDetailsUiSupport.createSectionMessage(packResult.summary())); + + if (packResult.result().emittedArtifacts().isEmpty()) { + content.getChildren().add(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_RESULT_NO_ARTIFACTS))); + } else { + final VBox artifacts = new VBox(8); + artifacts.getChildren().add(new Label(Container.i18n().text(I18n.ASSETS_PACK_WIZARD_LABEL_EMITTED_ARTIFACTS))); + for (PackerEmittedArtifactDTO artifact : packResult.result().emittedArtifacts()) { + artifacts.getChildren().add(AssetDetailsUiSupport.createKeyValueRow( + artifact.label(), + artifact.path().toString())); + } + content.getChildren().add(artifacts); + } + content.getChildren().add(AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(I18n.ASSETS_PACK_WIZARD_RESULT_COPY_FAILURES_HINT))); + stepBody.getChildren().setAll(content); + } + + private VBox createBusyBox(I18n messageKey) { + final ProgressIndicator indicator = new ProgressIndicator(); + indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS); + final VBox box = new VBox(16, indicator, AssetDetailsUiSupport.createSectionMessage( + Container.i18n().text(messageKey))); + box.setAlignment(Pos.CENTER_LEFT); + return box; + } + + private void goBack() { + if (phase == Phase.VALIDATION && !loadingValidation) { + phase = Phase.SUMMARY; + feedbackLabel.setText(""); + render(); + } + } + + private void loadSummary() { + loadingSummary = true; + feedbackLabel.setText(""); + summaryResult = null; + render(); + Container.backgroundTasks().submit(() -> { + try { + final PackWorkspaceSummaryResult result = Container.packer().workspaceService().getPackWorkspaceSummary( + new PackWorkspaceSummaryRequest(projectReference.toPackerProjectContext())); + Platform.runLater(() -> applySummaryResult(result)); + } catch (RuntimeException exception) { + Platform.runLater(() -> applySummaryFailure(exception)); + } + }); + } + + private void applySummaryResult(PackWorkspaceSummaryResult result) { + loadingSummary = false; + summaryResult = result; + feedbackLabel.setText(result.status() == PackerOperationStatus.FAILED ? result.summary() : ""); + render(); + } + + private void applySummaryFailure(RuntimeException exception) { + loadingSummary = false; + feedbackLabel.setText(extractMessage(exception, I18n.ASSETS_PACK_WIZARD_ERROR_SUMMARY)); + render(); + } + + private void loadValidation() { + if (summaryResult == null || loadingValidation) { + return; + } + phase = Phase.VALIDATION; + loadingValidation = true; + validationResult = null; + feedbackLabel.setText(""); + render(); + Container.backgroundTasks().submit(() -> { + try { + final ValidatePackWorkspaceResult result = Container.packer().workspaceService().validatePackWorkspace( + new ValidatePackWorkspaceRequest(projectReference.toPackerProjectContext())); + Platform.runLater(() -> applyValidationResult(result)); + } catch (RuntimeException exception) { + Platform.runLater(() -> applyValidationFailure(exception)); + } + }); + } + + private void applyValidationResult(ValidatePackWorkspaceResult result) { + loadingValidation = false; + validationResult = result; + if (!result.validation().canPack()) { + feedbackLabel.setText(result.summary()); + } else { + feedbackLabel.setText(""); + } + render(); + } + + private void applyValidationFailure(RuntimeException exception) { + loadingValidation = false; + feedbackLabel.setText(extractMessage(exception, I18n.ASSETS_PACK_WIZARD_ERROR_VALIDATION)); + render(); + } + + private void startPack() { + if (validationResult == null || !validationResult.validation().canPack() || packing) { + return; + } + phase = Phase.PACKING; + packing = true; + packResult = null; + feedbackLabel.setText(""); + render(); + Container.backgroundTasks().submit(() -> { + try { + final PackWorkspaceResult result = Container.packer().workspaceService().packWorkspace( + new PackWorkspaceRequest(projectReference.toPackerProjectContext())); + Platform.runLater(() -> applyPackResult(result)); + } catch (RuntimeException exception) { + Platform.runLater(() -> applyPackFailure(exception)); + } + }); + } + + private void applyPackResult(PackWorkspaceResult result) { + packing = false; + packResult = result; + phase = Phase.RESULT; + feedbackLabel.setText(result.status() == PackerOperationStatus.FAILED ? result.summary() : ""); + render(); + } + + private void applyPackFailure(RuntimeException exception) { + packing = false; + phase = Phase.RESULT; + feedbackLabel.setText(extractMessage(exception, I18n.ASSETS_PACK_WIZARD_ERROR_PACK)); + render(); + } + + private String extractMessage(RuntimeException exception, I18n fallbackKey) { + final String message = exception.getMessage(); + if (message == null || message.isBlank()) { + return Container.i18n().text(fallbackKey); + } + return message; + } + + private String formatElapsed(long elapsedMillis) { + final long seconds = elapsedMillis / 1000L; + final long milliseconds = elapsedMillis % 1000L; + return seconds + "." + String.format("%03d", milliseconds) + "s"; + } +} diff --git a/prometeu-studio/src/main/resources/i18n/messages.properties b/prometeu-studio/src/main/resources/i18n/messages.properties index bac36f5b..d5287541 100644 --- a/prometeu-studio/src/main/resources/i18n/messages.properties +++ b/prometeu-studio/src/main/resources/i18n/messages.properties @@ -240,4 +240,40 @@ assets.relocateWizard.error.name=Destination folder name is required. assets.relocateWizard.error.outsideAssets=The planned target root must stay inside assets/. assets.relocateWizard.error.targetAlreadyAsset=The planned target root already contains asset.json. assets.relocateWizard.error.targetSame=The planned target root must differ from the current asset root. +assets.packWizard.title=Pack Workspace +assets.packWizard.step.summary.title=Pack Summary +assets.packWizard.step.summary.description=Review the current build set before validating or packing it. +assets.packWizard.step.validation.title=Validation +assets.packWizard.step.validation.description=Inspect blocking diagnostics for included assets before starting the pack. +assets.packWizard.step.packing.title=Packing +assets.packWizard.step.packing.description=Wait while the packer emits assets.pa and companion artifacts. +assets.packWizard.step.result.title=Pack Result +assets.packWizard.step.result.description=Review the final status returned by the packer. +assets.packWizard.button.validate=Validate +assets.packWizard.button.pack=Pack +assets.packWizard.button.close=Close +assets.packWizard.button.copyFailures=Copy Failure Summary +assets.packWizard.loading.summary=Loading pack summary... +assets.packWizard.loading.validation=Running pack validation... +assets.packWizard.loading.packing=Packing assets... +assets.packWizard.label.canonicalArtifact=Canonical Artifact +assets.packWizard.label.includedAssets=Included Assets +assets.packWizard.label.outsideBuildSet=Outside Build Set +assets.packWizard.label.totalInScope=Assets In Scope +assets.packWizard.label.validAssets=Valid Assets +assets.packWizard.label.blockedAssets=Blocked Assets +assets.packWizard.label.status=Status +assets.packWizard.label.packedAssets=Packed Assets +assets.packWizard.label.elapsed=Elapsed +assets.packWizard.label.emittedArtifacts=Emitted Artifacts +assets.packWizard.status.ready=Ready to pack +assets.packWizard.status.blocked=Validation blocked +assets.packWizard.status.running=Packing in progress +assets.packWizard.status.finished=Packing finished +assets.packWizard.validation.empty=No validation entries are currently available. +assets.packWizard.result.noArtifacts=No emitted artifacts were reported. +assets.packWizard.result.copyFailuresHint=Failure summary export is reserved for a future iteration. +assets.packWizard.error.summary=Unable to load pack summary. +assets.packWizard.error.validation=Unable to validate the current pack set. +assets.packWizard.error.pack=Unable to pack the current build set. workspace.debug=Debug