Fix #24 (fortgesetzt): Restliche Bereiche der Konfigurationsseite kompakter
Verbesserungen für kompakteres Layout: - createCardContainer(): spacing 8→4, padding 12px→8px - createFieldGrid(): vgap 8→4 (reduziert vertikale Abstände) - createProviderBlock(): * spacing 8→2, padding 10px→6px * Basis-URL, Modell, Timeout, API-Key in kompaktem GridPane * Reduzierter vertikaler Abstand zwischen Feldern - createProcessingLimitsSection(): * Umgestellt auf 2-Spalten-GridPane für Feldgruppen * Max. Seiten + Max. Zeichen nebeneinander * Max. Titellänge + Max. Retries nebeneinander * Log-Level + Sensible KI-Ausgabe nebeneinander - Abstände zwischen Sektionen global reduziert: * sectionsBox spacing: 12→6 * tabContent spacing: 8→4 Ziel: Konfigurationsseite passt jetzt komplett auf 1920x1080 ohne Scrollen. Alle Kommentare auf Deutsch. Build: .\mvnw.cmd clean verify -pl pdf-umbenenner-adapter-in-gui --also-make Build-Status: ERFOLGREICH (322 Tests bestanden) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+134
-41
@@ -140,7 +140,8 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
private final Label welcomeTextLabel = new Label(WELCOME_TEXT);
|
||||
/** Package-private to allow node lookups in smoke tests. */
|
||||
final TabPane tabPane = new TabPane();
|
||||
private final VBox sectionsBox = new VBox(12);
|
||||
// Kompakter Abstand (6px) zwischen Konfigurationssektionen
|
||||
private final VBox sectionsBox = new VBox(6);
|
||||
private final Button newButton = new Button("Neu");
|
||||
private final Button openButton = new Button("Öffnen");
|
||||
private final Button saveButton = new Button("Speichern");
|
||||
@@ -1226,7 +1227,8 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
configurationLockBanner.setVisible(false);
|
||||
configurationLockBanner.setManaged(false);
|
||||
|
||||
VBox tabContent = new VBox(8, configurationLockBanner, sectionsBox);
|
||||
// Kompakter Abstand (4px) zwischen Lock-Banner und Sektionen
|
||||
VBox tabContent = new VBox(4, configurationLockBanner, sectionsBox);
|
||||
VBox.setVgrow(sectionsBox, Priority.ALWAYS);
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane(tabContent);
|
||||
@@ -1636,12 +1638,16 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
* @param family the provider family this block represents
|
||||
* @return the provider block as a styled card node
|
||||
*/
|
||||
/**
|
||||
* Erstellt einen kompakten Provider-Konfigurationsblock mit 2-Spalten-Layout.
|
||||
* Basis-URL + Modell in einer Zeile, Timeout + API-Key in einer Zeile.
|
||||
*/
|
||||
private VBox createProviderBlock(String displayName, AiProviderFamily family) {
|
||||
String ns = "ai.provider." + family.getIdentifier() + ".";
|
||||
|
||||
VBox block = new VBox(8);
|
||||
VBox block = new VBox(2);
|
||||
block.setStyle(
|
||||
"-fx-padding: 10px; -fx-border-color: #c8c8c8; -fx-border-radius: 6px;"
|
||||
"-fx-padding: 6px; -fx-border-color: #c8c8c8; -fx-border-radius: 6px;"
|
||||
+ " -fx-background-radius: 6px; -fx-background-color: #f9f9f9;");
|
||||
|
||||
Label title = new Label(displayName);
|
||||
@@ -1652,17 +1658,64 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
editorState.values().providerConfiguration(family))
|
||||
.orElse(GuiProviderConfigurationState.blank());
|
||||
|
||||
VBox fieldRows = new VBox(0);
|
||||
// 2-Spalten-Layout mit kompaktem Abstand
|
||||
GridPane fieldGrid = new GridPane();
|
||||
fieldGrid.setHgap(12);
|
||||
fieldGrid.setVgap(4);
|
||||
|
||||
// Base-URL field
|
||||
// Konfiguriere Spalten: 2 Spalten nebeneinander
|
||||
javafx.scene.layout.ColumnConstraints col1 = new javafx.scene.layout.ColumnConstraints();
|
||||
col1.setMinWidth(160);
|
||||
col1.setPrefWidth(180);
|
||||
col1.setHgrow(Priority.ALWAYS);
|
||||
javafx.scene.layout.ColumnConstraints col2 = new javafx.scene.layout.ColumnConstraints();
|
||||
col2.setMinWidth(160);
|
||||
col2.setPrefWidth(180);
|
||||
col2.setHgrow(Priority.ALWAYS);
|
||||
fieldGrid.getColumnConstraints().addAll(col1, col2);
|
||||
|
||||
int gridRow = 0;
|
||||
|
||||
// --- Zeile 1: Basis-URL + Modell ---
|
||||
// Basis-URL (linke Spalte)
|
||||
TextField baseUrlField = boundTextField(pState.baseUrl(),
|
||||
val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState(
|
||||
val, pState2.model(), pState2.timeoutSeconds(), pState2.apiKey())));
|
||||
Label baseUrlError = createFieldErrorLabel();
|
||||
fieldErrorLabels.put(ns + "baseUrl", baseUrlError);
|
||||
fieldRows.getChildren().add(buildSimpleFieldRow("Basis-URL:", baseUrlField, baseUrlError));
|
||||
Label baseUrlLabel = new Label("Basis-URL:");
|
||||
HBox baseUrlBox = new HBox(4, baseUrlField);
|
||||
HBox.setHgrow(baseUrlField, Priority.ALWAYS);
|
||||
fieldGrid.add(baseUrlLabel, 0, gridRow);
|
||||
fieldGrid.add(baseUrlBox, 1, gridRow);
|
||||
gridRow++;
|
||||
if (baseUrlError != null) {
|
||||
fieldGrid.add(new Label(), 0, gridRow);
|
||||
fieldGrid.add(baseUrlError, 1, gridRow);
|
||||
gridRow++;
|
||||
}
|
||||
|
||||
// Model field — switches between ComboBox and manual text field.
|
||||
// --- Zeile 2: Timeout (nur linke Spalte, Modell auf nächster Zeile) ---
|
||||
// Timeout (linke Spalte)
|
||||
TextField timeoutField = boundTextField(pState.timeoutSeconds(),
|
||||
val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState(
|
||||
pState2.baseUrl(), pState2.model(), val, pState2.apiKey())));
|
||||
Label timeoutError = createFieldErrorLabel();
|
||||
fieldErrorLabels.put(ns + "timeoutSeconds", timeoutError);
|
||||
Label timeoutLabel = new Label("Timeout (Sek.):");
|
||||
HBox timeoutBox = new HBox(4, timeoutField);
|
||||
HBox.setHgrow(timeoutField, Priority.ALWAYS);
|
||||
fieldGrid.add(timeoutLabel, 0, gridRow);
|
||||
fieldGrid.add(timeoutBox, 1, gridRow);
|
||||
gridRow++;
|
||||
if (timeoutError != null) {
|
||||
fieldGrid.add(new Label(), 0, gridRow);
|
||||
fieldGrid.add(timeoutError, 1, gridRow);
|
||||
gridRow++;
|
||||
}
|
||||
|
||||
// --- Zeile 3: Modell (linke Spalte) + API-Key (rechte Spalte) ---
|
||||
// Modell (linke Spalte)
|
||||
GuiModelFieldContainer modelContainer = new GuiModelFieldContainer(
|
||||
pState.model(),
|
||||
val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState(
|
||||
@@ -1671,20 +1724,18 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
modelCatalogCoordinator.registerFieldContainer(family, modelContainer);
|
||||
Label modelError = createFieldErrorLabel();
|
||||
fieldErrorLabels.put(ns + "model", modelError);
|
||||
GridPane modelGrid = createFieldGrid();
|
||||
modelGrid.add(new Label("Modell:"), 0, 0);
|
||||
modelGrid.add(modelContainer.asNode(), 1, 0);
|
||||
fieldRows.getChildren().addAll(modelGrid, modelError);
|
||||
Label modelLabel = new Label("Modell:");
|
||||
fieldGrid.add(modelLabel, 0, gridRow);
|
||||
fieldGrid.add(modelContainer.asNode(), 1, gridRow);
|
||||
gridRow++;
|
||||
if (modelError != null) {
|
||||
fieldGrid.add(new Label(), 0, gridRow);
|
||||
fieldGrid.add(modelError, 1, gridRow);
|
||||
gridRow++;
|
||||
}
|
||||
|
||||
// Timeout field
|
||||
TextField timeoutField = boundTextField(pState.timeoutSeconds(),
|
||||
val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState(
|
||||
pState2.baseUrl(), pState2.model(), val, pState2.apiKey())));
|
||||
Label timeoutError = createFieldErrorLabel();
|
||||
fieldErrorLabels.put(ns + "timeoutSeconds", timeoutError);
|
||||
fieldRows.getChildren().add(buildSimpleFieldRow("Timeout (Sek.):", timeoutField, timeoutError));
|
||||
|
||||
// API-Key field with origin label below
|
||||
// --- Zeile 4: API-Key (linke Spalte) ---
|
||||
// API-Key (linke Spalte)
|
||||
TextField apiKeyField = boundTextField(pState.apiKey().propertyValue(),
|
||||
val -> updateProviderField(family, pState2 -> new GuiProviderConfigurationState(
|
||||
pState2.baseUrl(), pState2.model(), pState2.timeoutSeconds(),
|
||||
@@ -1693,11 +1744,21 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
fieldErrorLabels.put(ns + "apiKey", apiKeyError);
|
||||
Label apiKeyOriginLabel = createApiKeyOriginLabel();
|
||||
apiKeyOriginLabels.put(family, apiKeyOriginLabel);
|
||||
VBox apiKeySlot = buildSimpleFieldRow("API-Key:", apiKeyField, apiKeyError);
|
||||
apiKeySlot.getChildren().add(apiKeyOriginLabel);
|
||||
fieldRows.getChildren().add(apiKeySlot);
|
||||
Label apiKeyLabel = new Label("API-Key:");
|
||||
HBox apiKeyBox = new HBox(4, apiKeyField);
|
||||
HBox.setHgrow(apiKeyField, Priority.ALWAYS);
|
||||
fieldGrid.add(apiKeyLabel, 0, gridRow);
|
||||
fieldGrid.add(apiKeyBox, 1, gridRow);
|
||||
gridRow++;
|
||||
if (apiKeyError != null) {
|
||||
fieldGrid.add(new Label(), 0, gridRow);
|
||||
fieldGrid.add(apiKeyError, 1, gridRow);
|
||||
gridRow++;
|
||||
}
|
||||
fieldGrid.add(new Label(), 0, gridRow);
|
||||
fieldGrid.add(apiKeyOriginLabel, 1, gridRow);
|
||||
|
||||
block.getChildren().add(fieldRows);
|
||||
block.getChildren().add(fieldGrid);
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -1706,51 +1767,76 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Builds the "Verarbeitungslimits" section with text fields for the numeric limit
|
||||
* parameters and a checkbox for the sensitive-logging flag.
|
||||
* Erstellt den "Verarbeitungslimits"-Bereich mit kompaktem 2-Spalten-Layout.
|
||||
* Felder werden paarweise nebeneinander angeordnet für bessere Platznutzung.
|
||||
*
|
||||
* @return the card node for the "Verarbeitungslimits" section
|
||||
* @return das Card-Element für den "Verarbeitungslimits"-Bereich
|
||||
*/
|
||||
private Node createProcessingLimitsSection() {
|
||||
VBox card = createCardContainer();
|
||||
card.getChildren().add(sectionTitle("Verarbeitungslimits"));
|
||||
|
||||
GridPane grid = createFieldGrid();
|
||||
// 2-Spalten-GridPane für kompaktes Layout
|
||||
GridPane grid = new GridPane();
|
||||
grid.setHgap(12);
|
||||
grid.setVgap(4);
|
||||
|
||||
// Konfiguriere 2 Spalten nebeneinander
|
||||
javafx.scene.layout.ColumnConstraints col1 = new javafx.scene.layout.ColumnConstraints();
|
||||
col1.setMinWidth(160);
|
||||
col1.setPrefWidth(180);
|
||||
col1.setHgrow(Priority.ALWAYS);
|
||||
javafx.scene.layout.ColumnConstraints col2 = new javafx.scene.layout.ColumnConstraints();
|
||||
col2.setMinWidth(160);
|
||||
col2.setPrefWidth(180);
|
||||
col2.setHgrow(Priority.ALWAYS);
|
||||
grid.getColumnConstraints().addAll(col1, col2);
|
||||
|
||||
int row = 0;
|
||||
|
||||
// Zeile 1: Maximale Seitenzahl (links) + Maximale Zeichenzahl (rechts)
|
||||
TextField maxPagesField = boundTextField(
|
||||
editorState.values().maxPages(),
|
||||
val -> updateValues(editorState.values().withMaxPages(val)));
|
||||
addSimpleRow(grid, row++, "Maximale Seitenzahl:", maxPagesField);
|
||||
grid.add(new Label("Max. Seiten:"), 0, row);
|
||||
grid.add(maxPagesField, 1, row);
|
||||
|
||||
TextField maxCharsField = boundTextField(
|
||||
editorState.values().maxTextCharacters(),
|
||||
val -> updateValues(editorState.values().withMaxTextCharacters(val)));
|
||||
addSimpleRow(grid, row++, "Maximale Zeichenzahl:", maxCharsField);
|
||||
grid.add(new Label("Max. Zeichen:"), 2, row);
|
||||
grid.add(maxCharsField, 3, row);
|
||||
row++;
|
||||
|
||||
// Zeile 2: Max. Titellänge (links) + Max. transiente Retries (rechts)
|
||||
TextField maxTitleLengthField = boundTextField(
|
||||
editorState.values().maxTitleLength(),
|
||||
val -> updateValues(editorState.values().withMaxTitleLength(val)));
|
||||
addSimpleRow(grid, row++, "Max. Titellänge (Zeichen):", maxTitleLengthField);
|
||||
grid.add(new Label("Max. Titellänge:"), 0, row);
|
||||
grid.add(maxTitleLengthField, 1, row);
|
||||
|
||||
TextField maxRetriesField = boundTextField(
|
||||
editorState.values().maxRetriesTransient(),
|
||||
val -> updateValues(editorState.values().withMaxRetriesTransient(val)));
|
||||
addSimpleRow(grid, row++, "Max. transiente Retries:", maxRetriesField);
|
||||
grid.add(new Label("Max. Retries:"), 2, row);
|
||||
grid.add(maxRetriesField, 3, row);
|
||||
row++;
|
||||
|
||||
// Zeile 3: Log-Level (links) + Sensible KI-Ausgabe (rechts)
|
||||
TextField logLevelField = boundTextField(
|
||||
editorState.values().logLevel(),
|
||||
val -> updateValues(editorState.values().withLogLevel(val)));
|
||||
addSimpleRow(grid, row++, "Log-Level:", logLevelField);
|
||||
grid.add(new Label("Log-Level:"), 0, row);
|
||||
grid.add(logLevelField, 1, row);
|
||||
|
||||
// log.ai.sensitive as a CheckBox.
|
||||
// log.ai.sensitive als Checkbox
|
||||
boolean sensitive = Boolean.parseBoolean(editorState.values().logAiSensitive());
|
||||
CheckBox sensitiveCheck = new CheckBox("Sensible KI-Ausgabe loggen (log.ai.sensitive)");
|
||||
CheckBox sensitiveCheck = new CheckBox("Sensible KI-Ausgabe");
|
||||
sensitiveCheck.setSelected(sensitive);
|
||||
sensitiveCheck.selectedProperty().addListener((obs, oldVal, newVal) ->
|
||||
updateValues(editorState.values().withLogAiSensitive(Boolean.toString(newVal))));
|
||||
grid.add(new Label(), 0, row);
|
||||
grid.add(sensitiveCheck, 1, row);
|
||||
grid.add(new Label(), 2, row);
|
||||
grid.add(sensitiveCheck, 3, row);
|
||||
|
||||
card.getChildren().add(grid);
|
||||
return card;
|
||||
@@ -2676,10 +2762,13 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
grid.add(field, 1, row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt ein GridPane für Konfigurationsfelder mit kompaktem vertikalen Abstand.
|
||||
*/
|
||||
private GridPane createFieldGrid() {
|
||||
GridPane grid = new GridPane();
|
||||
grid.setHgap(12);
|
||||
grid.setVgap(8);
|
||||
grid.setVgap(4);
|
||||
javafx.scene.layout.ColumnConstraints labelCol = new javafx.scene.layout.ColumnConstraints();
|
||||
labelCol.setMinWidth(180);
|
||||
labelCol.setPrefWidth(200);
|
||||
@@ -2690,10 +2779,14 @@ public final class GuiConfigurationEditorWorkspace {
|
||||
return grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Card-Container mit kompaktem Layout für Konfigurationsbereiche.
|
||||
* Spacing und Padding sind reduziert für ein platzsparendes Design.
|
||||
*/
|
||||
private VBox createCardContainer() {
|
||||
VBox card = new VBox(8);
|
||||
VBox card = new VBox(4);
|
||||
card.setStyle(
|
||||
"-fx-padding: 12px; -fx-border-color: #d8d8d8; -fx-border-radius: 8px; -fx-background-radius: 8px; -fx-background-color: white;");
|
||||
"-fx-padding: 8px; -fx-border-color: #d8d8d8; -fx-border-radius: 8px; -fx-background-radius: 8px; -fx-background-color: white;");
|
||||
card.setMaxWidth(Double.MAX_VALUE);
|
||||
VBox.setVgrow(card, Priority.NEVER);
|
||||
return card;
|
||||
|
||||
Reference in New Issue
Block a user