diff --git a/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java b/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java index 0d9f372..9e51f3b 100644 --- a/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java +++ b/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiConfigurationEditorWorkspace.java @@ -48,12 +48,16 @@ import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; +import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; import javafx.scene.control.ScrollPane; import javafx.scene.control.Separator; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TextField; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; @@ -328,7 +332,7 @@ public final class GuiConfigurationEditorWorkspace { this.configurationFileLoader = effectiveContext.configurationFileLoader(); this.configurationFileWriter = effectiveContext.configurationFileWriter(); this.editorState = effectiveContext.initialState(); - this.welcomeGuidanceVisible = editorState.isNewConfiguration(); + this.welcomeGuidanceVisible = false; this.apiKeyResolutionPort = effectiveContext.apiKeyResolutionPort(); this.modelCatalogCoordinator = new GuiModelCatalogCoordinator( @@ -1587,10 +1591,12 @@ public final class GuiConfigurationEditorWorkspace { claudeState.model(), claudeState.timeoutSeconds(), claudeKeyDescriptor, + claudeState.apiKey().propertyValue(), openaiState.baseUrl(), openaiState.model(), openaiState.timeoutSeconds(), - openaiKeyDescriptor); + openaiKeyDescriptor, + openaiState.apiKey().propertyValue()); } /** @@ -1644,11 +1650,10 @@ public final class GuiConfigurationEditorWorkspace { * writing anything to disk or making any network or filesystem calls. It is therefore * safe to call on the FX Application Thread at any time. *

- * In addition to updating the findings shown by the automatic validation, this action - * appends a dedicated INFO message to the central message area to confirm to the user - * that the action was explicitly executed and to report the number of findings found. - * The message uses a distinct source tag so that it can be replaced on subsequent - * executions without removing messages from other sources. + * In addition to updating the field-level findings shown by the automatic validation, + * this action appends a dedicated INFO confirmation message plus one message per concrete + * finding to the central message area. These entries accumulate across repeated clicks + * so the user can compare successive runs. *

* Differences from the automatic background validation: *

*

@@ -162,17 +162,18 @@ class GuiTechnicalTestCoordinatorSmokeTest { } // ========================================================================= - // Scenario: replace semantics – second trigger replaces previous entries + // Scenario: accumulation semantics – second trigger appends fresh entries // ========================================================================= /** - * Smoke test: triggering the coordinator twice replaces the previous SOURCE_TAG - * entries; the count remains the same as after a single trigger. + * Smoke test: triggering the coordinator twice accumulates both runs; the + * second trigger appends a fresh batch of SOURCE_TAG entries without + * removing the first batch. * * @throws Exception if the FX thread task fails or times out */ @Test - void trigger_twice_replacesPreviousTestEntries() throws Exception { + void trigger_twice_accumulatesTestEntries() throws Exception { runOnFx(() -> { List messages = new ArrayList<>(); GuiTechnicalTestCoordinator coordinator = buildSyncCoordinator(messages, report -> { }); @@ -189,8 +190,8 @@ class GuiTechnicalTestCoordinatorSmokeTest { && GuiTechnicalTestCoordinator.SOURCE_TAG.equals(m.source().get())) .count(); - assertEquals(countAfterFirst, countAfterSecond, - "Second trigger must replace (not append) the previous test entries"); + assertEquals(countAfterFirst * 2, countAfterSecond, + "Second trigger must append a fresh batch, doubling the SOURCE_TAG entries"); }); } @@ -247,9 +248,9 @@ class GuiTechnicalTestCoordinatorSmokeTest { "/src", "/tgt", "/db.sqlite", "/prompt.txt", "3", "10", "500", "https://api.anthropic.com", "claude-3-sonnet", "30", - EffectiveApiKeyDescriptor.absent(), + EffectiveApiKeyDescriptor.absent(), "", "https://api.openai.com", "gpt-4", "30", - EffectiveApiKeyDescriptor.absent())); + EffectiveApiKeyDescriptor.absent(), "")); TechnicalTestOrchestrator orchestrator = new TechnicalTestOrchestrator( new EditorConfigurationValidator(), @@ -283,9 +284,9 @@ class GuiTechnicalTestCoordinatorSmokeTest { "/src", "/tgt", "/db.sqlite", "/prompt.txt", "3", "10", "500", "https://api.anthropic.com", "claude-3-sonnet", "30", - EffectiveApiKeyDescriptor.absent(), + EffectiveApiKeyDescriptor.absent(), "", "https://api.openai.com", "gpt-4", "30", - EffectiveApiKeyDescriptor.absent())); + EffectiveApiKeyDescriptor.absent(), "")); // Second trigger with the updated (unsaved) input. coordinator.triggerTechnicalTests(); @@ -370,9 +371,9 @@ class GuiTechnicalTestCoordinatorSmokeTest { "/src", "/tgt", "/db.sqlite", "/prompt.txt", "3", "10", "2000", "https://api.anthropic.com", "claude-3-sonnet", "30", - EffectiveApiKeyDescriptor.absent(), + EffectiveApiKeyDescriptor.absent(), "", "https://api.openai.com", "gpt-4", "30", - EffectiveApiKeyDescriptor.absent()); + EffectiveApiKeyDescriptor.absent(), ""); GuiTechnicalTestCoordinator coordinator = new GuiTechnicalTestCoordinator( orchestrator, diff --git a/pdf-umbenenner-adapter-in-gui/src/test/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiValidateActionSmokeTest.java b/pdf-umbenenner-adapter-in-gui/src/test/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiValidateActionSmokeTest.java index c42030f..b91f9b4 100644 --- a/pdf-umbenenner-adapter-in-gui/src/test/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiValidateActionSmokeTest.java +++ b/pdf-umbenenner-adapter-in-gui/src/test/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/GuiValidateActionSmokeTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorState; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorStateFactory; +import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationTemplateFactory; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiEditorValidationResult; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiMessageEntry; import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiMessageSeverity; @@ -34,11 +35,11 @@ import javafx.scene.control.Button; *

Covered scenarios

*