Fix doppelte API-Key-Meldung: originLabel zeigt nur noch ENV-Hinweis
Der API-Key-Herkunfts-Label (apiKeyOriginLabel) zeigte bisher sowohl INFO-Befunde (Schlüssel kommt aus Umgebungsvariable) als auch WARNING/ERROR-Befunde (Schlüssel fehlt) an. Da das fieldErrorLabel direkt darunter dieselben WARNING/ERROR-Befunde bereits anzeigt, erschien die „Kein API-Key"-Meldung zweimal im selben Bereich. Lösung: refreshApiKeyOriginLabels() wertet nur noch INFO-Befunde aus. WARNING/ERROR-Befunde für fehlende API-Keys werden ausschließlich vom fieldErrorLabel angezeigt. STYLE_ORIGIN_MISSING entfernt. Drei neue Smoke-Tests sichern das Verhalten ab: - apiKeyAbsent_originLabelHidden - apiKeyAbsent_fieldErrorLabelVisible - apiKeyAbsent_noDuplicateMessageInPendingMessages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+12
-22
@@ -1967,14 +1967,14 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
/**
|
||||
* Updates the API-key origin labels below each provider's API-key field.
|
||||
* <p>
|
||||
* The display logic follows the effective-key precedence order:
|
||||
* <ol>
|
||||
* <li>If the effective key comes from an environment variable, the label shows the
|
||||
* variable name in an informational style.</li>
|
||||
* <li>If the property value is filled and no environment variable overrides it, the label
|
||||
* is hidden.</li>
|
||||
* <li>If no key source is effective, the label shows a warning in the field-error style.</li>
|
||||
* </ol>
|
||||
* The label is shown exclusively when the effective key comes from an environment variable
|
||||
* (INFO finding). In all other cases the label is hidden:
|
||||
* <ul>
|
||||
* <li>Key from properties file: label hidden (no action required).</li>
|
||||
* <li>Key absent (WARNING finding): label hidden — the field-error label registered in
|
||||
* {@link #fieldErrorLabels} already displays this finding directly below the field;
|
||||
* showing it a second time in the origin label would produce a visible duplicate.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The origin information is derived from the pending field findings produced by the validator,
|
||||
* which already resolved the API-key precedence for both providers.
|
||||
@@ -1988,28 +1988,20 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
String apiKeyField = "ai.provider." + family.getIdentifier() + ".apiKey";
|
||||
|
||||
// Look for an INFO finding about ENV-variable origin for this provider.
|
||||
// WARNING/ERROR findings (missing key) are intentionally excluded here:
|
||||
// those are already shown by the field-error label registered in fieldErrorLabels,
|
||||
// and repeating them in the origin label would cause the same text to appear twice
|
||||
// in close proximity below the API-key field.
|
||||
Optional<GuiFieldFinding> envFinding = pendingFieldFindings.stream()
|
||||
.filter(f -> apiKeyField.equals(f.fieldKey()))
|
||||
.filter(f -> f.severity() == GuiMessageSeverity.INFO)
|
||||
.findFirst();
|
||||
|
||||
// Look for an ERROR/WARNING finding about missing key for this provider.
|
||||
Optional<GuiFieldFinding> missingFinding = pendingFieldFindings.stream()
|
||||
.filter(f -> apiKeyField.equals(f.fieldKey()))
|
||||
.filter(f -> f.severity() == GuiMessageSeverity.ERROR
|
||||
|| f.severity() == GuiMessageSeverity.WARNING)
|
||||
.findFirst();
|
||||
|
||||
if (envFinding.isPresent()) {
|
||||
label.setText(envFinding.get().text());
|
||||
label.setStyle(STYLE_ORIGIN_INFO);
|
||||
label.setVisible(true);
|
||||
label.setManaged(true);
|
||||
} else if (missingFinding.isPresent()) {
|
||||
label.setText(missingFinding.get().text());
|
||||
label.setStyle(STYLE_ORIGIN_MISSING);
|
||||
label.setVisible(true);
|
||||
label.setManaged(true);
|
||||
} else {
|
||||
label.setText("");
|
||||
label.setVisible(false);
|
||||
@@ -2020,8 +2012,6 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
|
||||
private static final String STYLE_ORIGIN_INFO =
|
||||
"-fx-font-size: 11px; -fx-text-fill: #1565c0; -fx-padding: 0 0 4px 0;";
|
||||
private static final String STYLE_ORIGIN_MISSING =
|
||||
"-fx-font-size: 11px; -fx-text-fill: #b71c1c; -fx-padding: 0 0 4px 0;";
|
||||
|
||||
// =========================================================================
|
||||
// Path picker helpers
|
||||
|
||||
+73
@@ -361,6 +361,79 @@ class GuiMessageAreaSmokeTest {
|
||||
});
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Scenario: absent API key — origin label hidden, no duplicate in message area
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Smoke test: when no API key is configured and no environment variable provides one, the
|
||||
* api-key origin label below the Claude API-key field must be hidden (not visible).
|
||||
* <p>
|
||||
* The field-error label (registered in {@code fieldErrorLabels}) already shows the warning
|
||||
* below the input field; duplicating the same text in the origin label would cause the same
|
||||
* message to appear twice in close visual proximity. The origin label is therefore hidden
|
||||
* for the absent-key case.
|
||||
*/
|
||||
@Test
|
||||
void apiKeyAbsent_originLabelHidden() throws Exception {
|
||||
runOnFx(() -> {
|
||||
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
|
||||
ws.requestNewConfiguration();
|
||||
|
||||
// Standard template has active provider = Claude but no API key value.
|
||||
Label originLabel = ws.apiKeyOriginLabels.get(AiProviderFamily.CLAUDE);
|
||||
assertNotNull(originLabel,
|
||||
"An api-key origin label must be registered for AiProviderFamily.CLAUDE");
|
||||
assertFalse(originLabel.isVisible(),
|
||||
"Claude api-key origin label must be HIDDEN when no API key is configured "
|
||||
+ "— the field-error label already shows the warning, so the origin label "
|
||||
+ "must not repeat it");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoke test: when no API key is configured, the field-error label registered for
|
||||
* {@code ai.provider.claude.apiKey} must be visible and carry a non-blank warning text.
|
||||
* <p>
|
||||
* This is the single intended location for the missing-key warning below the input field.
|
||||
*/
|
||||
@Test
|
||||
void apiKeyAbsent_fieldErrorLabelVisible() throws Exception {
|
||||
runOnFx(() -> {
|
||||
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
|
||||
ws.requestNewConfiguration();
|
||||
|
||||
Label errorLabel = ws.fieldErrorLabels.get("ai.provider.claude.apiKey");
|
||||
assertNotNull(errorLabel,
|
||||
"A field-error label must be registered for 'ai.provider.claude.apiKey'");
|
||||
assertTrue(errorLabel.isVisible(),
|
||||
"api-key field-error label must be visible when no API key is configured");
|
||||
assertFalse(errorLabel.getText().isBlank(),
|
||||
"api-key field-error label must carry a non-blank warning text");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoke test: when no API key is configured, the text of the missing-key warning must appear
|
||||
* exactly once in {@code pendingMessages}. Having the same text twice would mean two
|
||||
* validation sources independently write the same finding to the central message area.
|
||||
*/
|
||||
@Test
|
||||
void apiKeyAbsent_noDuplicateMessageInPendingMessages() throws Exception {
|
||||
runOnFx(() -> {
|
||||
GuiConfigurationEditorWorkspace ws = new GuiConfigurationEditorWorkspace(Optional.empty());
|
||||
ws.requestNewConfiguration();
|
||||
|
||||
// Collect all message texts that contain the canonical "Kein API-Schlüssel" fragment.
|
||||
long count = ws.pendingMessages.stream()
|
||||
.filter(m -> m.text().contains("API-Schlüssel") || m.text().contains("API-Key"))
|
||||
.count();
|
||||
assertTrue(count <= 1,
|
||||
"The missing-API-key finding must appear at most once in pendingMessages, "
|
||||
+ "but found " + count + " occurrences");
|
||||
});
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Scenario: INFO-coloured prefix in the message area (model-catalogue success)
|
||||
// =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user