From ada7e203e38bf50b988f4ad0ec84fcc597ba2c2b Mon Sep 17 00:00:00 2001 From: Marcus van Elst Date: Tue, 21 Apr 2026 16:04:15 +0200 Subject: [PATCH] =?UTF-8?q?GUI-Bugfixes:=20Defaults=20beim=20Start,=20kopi?= =?UTF-8?q?erbare=20Meldungen=20mit=20Zeitstempel,=20Befundauflistung,=20M?= =?UTF-8?q?odell-ComboBox=20links,=20effektiver=20API-Key=20f=C3=BCr=20Mod?= =?UTF-8?q?ellabruf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Blank-Startzustand zeigt jetzt die Standardvorlage (wie nach "Neu"), neue Factory createEmptyStartState für Tests - Meldungsbereich ist per Kontextmenü bzw. Strg+C kopierbar - Jede Meldung trägt ein führendes [HH:mm:ss]-Präfix - Validieren- und Tests-Aktionen akkumulieren Meldungen, automatische Validierung ersetzt still ihre Einträge - Validieren-Meldung listet alle konkreten Befunde einzeln auf - Modell-ComboBox und manuelles Modellfeld sind linksbündig - ApiKeyResolutionPort liefert jetzt den effektiven API-Schlüsselwert (Default + Env-Adapter-Override), so dass der Modellliste-Test in den technischen Tests nicht mehr "API-Schlüssel fehlt" meldet, obwohl er gesetzt ist --- .../gui/GuiConfigurationEditorWorkspace.java | 153 +++++++++++++++--- .../in/gui/GuiTechnicalTestCoordinator.java | 9 +- .../GuiConfigurationTemplateFactory.java | 23 ++- .../in/gui/editor/GuiModelFieldContainer.java | 2 + .../adapter/in/gui/GuiAdapterSmokeTest.java | 12 +- .../in/gui/GuiEditorIntegrationTest.java | 24 +-- .../in/gui/GuiEditorRegressionSmokeTest.java | 30 ++-- .../GuiTechnicalTestCoordinatorSmokeTest.java | 27 ++-- .../in/gui/GuiValidateActionSmokeTest.java | 87 +++++----- .../GuiConfigurationTemplateFactoryTest.java | 18 ++- .../EnvironmentApiKeyResolutionAdapter.java | 45 ++++++ .../editor/ApiKeyResolutionPort.java | 31 ++++ .../editor/EditorValidationInput.java | 10 +- .../ProviderTechnicalTestService.java | 39 +++-- .../EditorConfigurationValidatorTest.java | 108 +++++++------ .../ProviderTechnicalTestServiceTest.java | 37 ++++- .../TechnicalTestOrchestratorTest.java | 16 +- .../TechnicalTestRequestTest.java | 4 +- 18 files changed, 471 insertions(+), 204 deletions(-) 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

*