Erweiterungen
This commit is contained in:
@@ -11,6 +11,8 @@ import org.springframework.data.mongodb.core.mapping.Document;
|
|||||||
import org.springframework.data.mongodb.core.mapping.Field;
|
import org.springframework.data.mongodb.core.mapping.Field;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@@ -28,6 +30,13 @@ public class TaskEntry {
|
|||||||
@Field("text")
|
@Field("text")
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
|
@Field("task_type")
|
||||||
|
private TaskType taskType = TaskType.CONFIRMATION;
|
||||||
|
|
||||||
|
// Task-specific configuration data
|
||||||
|
@Field("configuration")
|
||||||
|
private TaskConfiguration configuration;
|
||||||
|
|
||||||
// Completion tracking
|
// Completion tracking
|
||||||
@Field("completed")
|
@Field("completed")
|
||||||
private boolean completed = false;
|
private boolean completed = false;
|
||||||
@@ -58,5 +67,51 @@ public class TaskEntry {
|
|||||||
public String getJobIdAsString() {
|
public String getJobIdAsString() {
|
||||||
return jobId != null ? jobId.toString() : null;
|
return jobId != null ? jobId.toString() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum for different task types
|
||||||
|
*/
|
||||||
|
public enum TaskType {
|
||||||
|
CONFIRMATION("Bestätigung"),
|
||||||
|
SIGNATURE("Unterschrift"),
|
||||||
|
TODOLIST("To-Do Liste"),
|
||||||
|
PHOTO("Foto"),
|
||||||
|
BARCODE("Barcode");
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
|
TaskType(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration data for different task types
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class TaskConfiguration {
|
||||||
|
// For CONFIRMATION: button text
|
||||||
|
private String buttonText;
|
||||||
|
|
||||||
|
// For TODOLIST: list of todo items
|
||||||
|
private List<String> todoItems;
|
||||||
|
|
||||||
|
// For PHOTO: min and max photo count
|
||||||
|
private Integer minPhotoCount;
|
||||||
|
private Integer maxPhotoCount;
|
||||||
|
|
||||||
|
// For BARCODE: min and max barcode count
|
||||||
|
private Integer minBarcodeCount;
|
||||||
|
private Integer maxBarcodeCount;
|
||||||
|
|
||||||
|
// Generic configuration map for future extensions
|
||||||
|
private Map<String, Object> additionalConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ public class AddJobView extends Main {
|
|||||||
private com.vaadin.flow.component.tabs.Tab addressesTab;
|
private com.vaadin.flow.component.tabs.Tab addressesTab;
|
||||||
private com.vaadin.flow.component.tabs.Tab appointmentsTab;
|
private com.vaadin.flow.component.tabs.Tab appointmentsTab;
|
||||||
private com.vaadin.flow.component.tabs.Tab cargoTab;
|
private com.vaadin.flow.component.tabs.Tab cargoTab;
|
||||||
|
private com.vaadin.flow.component.tabs.Tab tasksTab;
|
||||||
private com.vaadin.flow.component.tabs.Tab priceTab;
|
private com.vaadin.flow.component.tabs.Tab priceTab;
|
||||||
|
|
||||||
// Submit button
|
// Submit button
|
||||||
@@ -327,10 +328,13 @@ public class AddJobView extends Main {
|
|||||||
// Tab 2: Appointments & Processing
|
// Tab 2: Appointments & Processing
|
||||||
appointmentsTab = tabSheet.add("Termine & Verarbeitung", createAppointmentsAndProcessingTab());
|
appointmentsTab = tabSheet.add("Termine & Verarbeitung", createAppointmentsAndProcessingTab());
|
||||||
|
|
||||||
// Tab 3: Cargo & Tasks
|
// Tab 3: Cargo
|
||||||
cargoTab = tabSheet.add("Ladung & Aufgaben", createCargoAndTasksTab());
|
cargoTab = tabSheet.add("Ladung", createCargoTab());
|
||||||
|
|
||||||
// Tab 4: Price & Submit
|
// Tab 4: Tasks
|
||||||
|
tasksTab = tabSheet.add("Aufgaben", createTasksTab());
|
||||||
|
|
||||||
|
// Tab 5: Price & Submit
|
||||||
priceTab = tabSheet.add("Preis & Abschluss", createPriceAndSubmitTab());
|
priceTab = tabSheet.add("Preis & Abschluss", createPriceAndSubmitTab());
|
||||||
|
|
||||||
add(tabSheet);
|
add(tabSheet);
|
||||||
@@ -436,7 +440,7 @@ public class AddJobView extends Main {
|
|||||||
return tabContent;
|
return tabContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component createCargoAndTasksTab() {
|
private Component createCargoTab() {
|
||||||
VerticalLayout tabContent = new VerticalLayout();
|
VerticalLayout tabContent = new VerticalLayout();
|
||||||
tabContent.setSizeFull();
|
tabContent.setSizeFull();
|
||||||
tabContent.setPadding(true);
|
tabContent.setPadding(true);
|
||||||
@@ -445,6 +449,15 @@ public class AddJobView extends Main {
|
|||||||
// Add cargo section
|
// Add cargo section
|
||||||
tabContent.add(createCargoSection());
|
tabContent.add(createCargoSection());
|
||||||
|
|
||||||
|
return tabContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component createTasksTab() {
|
||||||
|
VerticalLayout tabContent = new VerticalLayout();
|
||||||
|
tabContent.setSizeFull();
|
||||||
|
tabContent.setPadding(true);
|
||||||
|
tabContent.setSpacing(true);
|
||||||
|
|
||||||
// Add tasks and notes section
|
// Add tasks and notes section
|
||||||
tabContent.add(createTasksAndNotesSection());
|
tabContent.add(createTasksAndNotesSection());
|
||||||
|
|
||||||
@@ -915,7 +928,8 @@ public class AddJobView extends Main {
|
|||||||
// Check validation state for each tab and update labels with exclamation marks
|
// Check validation state for each tab and update labels with exclamation marks
|
||||||
updateTabLabel(addressesTab, "Auftraggeber & Adressen", hasAddressValidationErrors());
|
updateTabLabel(addressesTab, "Auftraggeber & Adressen", hasAddressValidationErrors());
|
||||||
updateTabLabel(appointmentsTab, "Termine & Verarbeitung", hasAppointmentValidationErrors());
|
updateTabLabel(appointmentsTab, "Termine & Verarbeitung", hasAppointmentValidationErrors());
|
||||||
updateTabLabel(cargoTab, "Ladung & Aufgaben", hasCargoValidationErrors());
|
updateTabLabel(cargoTab, "Ladung", hasCargoValidationErrors());
|
||||||
|
updateTabLabel(tasksTab, "Aufgaben", hasTasksValidationErrors());
|
||||||
updateTabLabel(priceTab, "Preis & Abschluss", hasPriceValidationErrors());
|
updateTabLabel(priceTab, "Preis & Abschluss", hasPriceValidationErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -969,6 +983,11 @@ public class AddJobView extends Main {
|
|||||||
return !allCargoItemsValid; // Return true if ANY cargo item is incomplete (show warning)
|
return !allCargoItemsValid; // Return true if ANY cargo item is incomplete (show warning)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasTasksValidationErrors() {
|
||||||
|
// Tasks are optional, so no validation errors for tasks
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasPriceValidationErrors() {
|
private boolean hasPriceValidationErrors() {
|
||||||
return isFieldEmpty(price);
|
return isFieldEmpty(price);
|
||||||
}
|
}
|
||||||
@@ -1066,9 +1085,9 @@ public class AddJobView extends Main {
|
|||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Other errors
|
// Other errors
|
||||||
// Reset cargo error
|
// Reset cargo error
|
||||||
if (cargoError != null) cargoError.setVisible(false);
|
if (cargoError != null) cargoError.setVisible(false);
|
||||||
if (cargoAreaContainer != null) cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
if (cargoAreaContainer != null) cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||||
Notification errorNotification = Notification.show(
|
Notification errorNotification = Notification.show(
|
||||||
"Fehler beim Erstellen des Auftrags: " + e.getMessage());
|
"Fehler beim Erstellen des Auftrags: " + e.getMessage());
|
||||||
errorNotification.setDuration(5000);
|
errorNotification.setDuration(5000);
|
||||||
@@ -1265,31 +1284,7 @@ public class AddJobView extends Main {
|
|||||||
tasksList.setSpacing(true);
|
tasksList.setSpacing(true);
|
||||||
|
|
||||||
java.util.function.Consumer<Void> addTask = (v) -> {
|
java.util.function.Consumer<Void> addTask = (v) -> {
|
||||||
HorizontalLayout row = new HorizontalLayout();
|
createTaskRow();
|
||||||
row.setWidthFull();
|
|
||||||
row.setAlignItems(FlexComponent.Alignment.END);
|
|
||||||
|
|
||||||
TextField taskField = new TextField();
|
|
||||||
taskField.setPlaceholder("Aufgabe");
|
|
||||||
taskField.setWidth("100%");
|
|
||||||
|
|
||||||
Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
|
|
||||||
remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
|
|
||||||
remove.addClickListener(e -> {
|
|
||||||
int idx = tasksList.getChildren().toList().indexOf(row);
|
|
||||||
if (idx >= 0 && idx < tasksState.size()) tasksState.remove(idx);
|
|
||||||
tasksList.remove(row);
|
|
||||||
});
|
|
||||||
|
|
||||||
row.add(taskField, remove);
|
|
||||||
row.setFlexGrow(1, taskField);
|
|
||||||
tasksList.add(row);
|
|
||||||
|
|
||||||
// Keep backing tasks list in sync
|
|
||||||
TaskEntry te = new TaskEntry();
|
|
||||||
te.setText(taskField.getValue());
|
|
||||||
tasksState.add(te);
|
|
||||||
taskField.addValueChangeListener(ev -> te.setText(ev.getValue()));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 1 Beispielzeile
|
// 1 Beispielzeile
|
||||||
@@ -1458,4 +1453,226 @@ public class AddJobView extends Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createTaskRow() {
|
||||||
|
VerticalLayout taskContainer = new VerticalLayout();
|
||||||
|
taskContainer.setPadding(true);
|
||||||
|
taskContainer.setSpacing(true);
|
||||||
|
taskContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
|
||||||
|
taskContainer.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
|
||||||
|
taskContainer.getStyle().set("background-color", "var(--lumo-base-color)");
|
||||||
|
taskContainer.getStyle().set("position", "relative");
|
||||||
|
|
||||||
|
|
||||||
|
// Task type selection
|
||||||
|
ComboBox<TaskEntry.TaskType> taskTypeCombo = new ComboBox<>("Aufgabentyp");
|
||||||
|
taskTypeCombo.setItems(TaskEntry.TaskType.values());
|
||||||
|
taskTypeCombo.setItemLabelGenerator(TaskEntry.TaskType::getDisplayName);
|
||||||
|
taskTypeCombo.setPlaceholder("Aufgabentyp wählen...");
|
||||||
|
taskTypeCombo.setWidthFull();
|
||||||
|
|
||||||
|
// Configuration container for dynamic fields
|
||||||
|
VerticalLayout configContainer = new VerticalLayout();
|
||||||
|
configContainer.setPadding(false);
|
||||||
|
configContainer.setSpacing(true);
|
||||||
|
|
||||||
|
// Red X button positioned in top-right corner
|
||||||
|
Button deleteXButton = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
|
||||||
|
deleteXButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
|
||||||
|
deleteXButton.getStyle().set("position", "absolute");
|
||||||
|
deleteXButton.getStyle().set("top", "8px");
|
||||||
|
deleteXButton.getStyle().set("right", "8px");
|
||||||
|
deleteXButton.getStyle().set("z-index", "10");
|
||||||
|
deleteXButton.getStyle().set("padding", "4px");
|
||||||
|
deleteXButton.getStyle().set("min-width", "24px");
|
||||||
|
deleteXButton.getStyle().set("min-height", "24px");
|
||||||
|
deleteXButton.addClickListener(e -> {
|
||||||
|
int idx = tasksList.getChildren().toList().indexOf(taskContainer);
|
||||||
|
if (idx >= 0 && idx < tasksState.size()) tasksState.remove(idx);
|
||||||
|
tasksList.remove(taskContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
taskContainer.add(taskTypeCombo, configContainer);
|
||||||
|
taskContainer.add(deleteXButton);
|
||||||
|
|
||||||
|
// Create TaskEntry and add to state
|
||||||
|
TaskEntry taskEntry = new TaskEntry();
|
||||||
|
taskEntry.setText("");
|
||||||
|
taskEntry.setTaskType(TaskEntry.TaskType.CONFIRMATION);
|
||||||
|
taskEntry.setConfiguration(new TaskEntry.TaskConfiguration());
|
||||||
|
tasksState.add(taskEntry);
|
||||||
|
|
||||||
|
taskTypeCombo.addValueChangeListener(ev -> {
|
||||||
|
TaskEntry.TaskType selectedType = ev.getValue();
|
||||||
|
if (selectedType != null) {
|
||||||
|
taskEntry.setTaskType(selectedType);
|
||||||
|
updateTaskConfiguration(configContainer, taskEntry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set initial configuration
|
||||||
|
taskTypeCombo.setValue(TaskEntry.TaskType.CONFIRMATION);
|
||||||
|
updateTaskConfiguration(configContainer, taskEntry);
|
||||||
|
|
||||||
|
tasksList.add(taskContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTaskConfiguration(VerticalLayout configContainer, TaskEntry taskEntry) {
|
||||||
|
configContainer.removeAll();
|
||||||
|
|
||||||
|
TaskEntry.TaskType taskType = taskEntry.getTaskType();
|
||||||
|
if (taskType == null) return;
|
||||||
|
|
||||||
|
// Ensure configuration is initialized
|
||||||
|
if (taskEntry.getConfiguration() == null) {
|
||||||
|
taskEntry.setConfiguration(new TaskEntry.TaskConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (taskType) {
|
||||||
|
case CONFIRMATION:
|
||||||
|
TextField buttonTextField = new TextField("Button-Text");
|
||||||
|
buttonTextField.setPlaceholder("z.B. 'Bestätigen', 'Abgeschlossen'");
|
||||||
|
buttonTextField.setWidthFull();
|
||||||
|
buttonTextField.setValue(taskEntry.getConfiguration().getButtonText() != null ?
|
||||||
|
taskEntry.getConfiguration().getButtonText() : "");
|
||||||
|
buttonTextField.addValueChangeListener(ev -> {
|
||||||
|
taskEntry.getConfiguration().setButtonText(ev.getValue());
|
||||||
|
});
|
||||||
|
configContainer.add(buttonTextField);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIGNATURE:
|
||||||
|
// No additional configuration needed
|
||||||
|
Span info = new Span("Keine zusätzliche Konfiguration erforderlich");
|
||||||
|
info.getStyle().set("color", "var(--lumo-secondary-text-color)");
|
||||||
|
info.getStyle().set("font-style", "italic");
|
||||||
|
configContainer.add(info);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TODOLIST:
|
||||||
|
VerticalLayout todoContainer = new VerticalLayout();
|
||||||
|
todoContainer.setPadding(false);
|
||||||
|
todoContainer.setSpacing(true);
|
||||||
|
|
||||||
|
H3 todoTitle = new H3("To-Do Punkte");
|
||||||
|
todoTitle.getStyle().set("margin", "0");
|
||||||
|
todoContainer.add(todoTitle);
|
||||||
|
|
||||||
|
// Dynamic todo list
|
||||||
|
VerticalLayout todoList = new VerticalLayout();
|
||||||
|
todoList.setPadding(false);
|
||||||
|
todoList.setSpacing(true);
|
||||||
|
|
||||||
|
java.util.function.Consumer<Void> addTodoItem = (v) -> {
|
||||||
|
HorizontalLayout todoRow = new HorizontalLayout();
|
||||||
|
todoRow.setWidthFull();
|
||||||
|
todoRow.setAlignItems(FlexComponent.Alignment.END);
|
||||||
|
|
||||||
|
TextField todoField = new TextField();
|
||||||
|
todoField.setPlaceholder("To-Do Punkt");
|
||||||
|
todoField.setWidth("100%");
|
||||||
|
|
||||||
|
Button removeTodo = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
|
||||||
|
removeTodo.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
|
||||||
|
removeTodo.addClickListener(e -> {
|
||||||
|
todoList.remove(todoRow);
|
||||||
|
updateTodoItems(todoList, taskEntry);
|
||||||
|
});
|
||||||
|
|
||||||
|
todoRow.add(todoField, removeTodo);
|
||||||
|
todoRow.setFlexGrow(1, todoField);
|
||||||
|
todoList.add(todoRow);
|
||||||
|
|
||||||
|
todoField.addValueChangeListener(ev -> updateTodoItems(todoList, taskEntry));
|
||||||
|
};
|
||||||
|
|
||||||
|
Button addTodoBtn = new Button("To-Do Punkt hinzufügen", new Icon(VaadinIcon.PLUS));
|
||||||
|
addTodoBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||||
|
addTodoBtn.addClickListener(e -> addTodoItem.accept(null));
|
||||||
|
|
||||||
|
// Add initial todo item
|
||||||
|
addTodoItem.accept(null);
|
||||||
|
|
||||||
|
todoContainer.add(todoList, addTodoBtn);
|
||||||
|
configContainer.add(todoContainer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PHOTO:
|
||||||
|
HorizontalLayout photoLayout = new HorizontalLayout();
|
||||||
|
photoLayout.setWidthFull();
|
||||||
|
photoLayout.setSpacing(true);
|
||||||
|
|
||||||
|
IntegerField minPhotos = new IntegerField("Min. Anzahl Fotos");
|
||||||
|
minPhotos.setPlaceholder("1");
|
||||||
|
minPhotos.setMin(1);
|
||||||
|
minPhotos.setValue(taskEntry.getConfiguration().getMinPhotoCount() != null ?
|
||||||
|
taskEntry.getConfiguration().getMinPhotoCount() : 1);
|
||||||
|
|
||||||
|
IntegerField maxPhotos = new IntegerField("Max. Anzahl Fotos");
|
||||||
|
maxPhotos.setPlaceholder("10");
|
||||||
|
maxPhotos.setMin(1);
|
||||||
|
maxPhotos.setValue(taskEntry.getConfiguration().getMaxPhotoCount() != null ?
|
||||||
|
taskEntry.getConfiguration().getMaxPhotoCount() : 10);
|
||||||
|
|
||||||
|
photoLayout.add(minPhotos, maxPhotos);
|
||||||
|
|
||||||
|
minPhotos.addValueChangeListener(ev -> {
|
||||||
|
taskEntry.getConfiguration().setMinPhotoCount(ev.getValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
maxPhotos.addValueChangeListener(ev -> {
|
||||||
|
taskEntry.getConfiguration().setMaxPhotoCount(ev.getValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
configContainer.add(photoLayout);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BARCODE:
|
||||||
|
HorizontalLayout barcodeLayout = new HorizontalLayout();
|
||||||
|
barcodeLayout.setWidthFull();
|
||||||
|
barcodeLayout.setSpacing(true);
|
||||||
|
|
||||||
|
IntegerField minBarcodes = new IntegerField("Min. Anzahl Barcodes");
|
||||||
|
minBarcodes.setPlaceholder("1");
|
||||||
|
minBarcodes.setMin(1);
|
||||||
|
minBarcodes.setValue(taskEntry.getConfiguration().getMinBarcodeCount() != null ?
|
||||||
|
taskEntry.getConfiguration().getMinBarcodeCount() : 1);
|
||||||
|
|
||||||
|
IntegerField maxBarcodes = new IntegerField("Max. Anzahl Barcodes");
|
||||||
|
maxBarcodes.setPlaceholder("10");
|
||||||
|
maxBarcodes.setMin(1);
|
||||||
|
maxBarcodes.setValue(taskEntry.getConfiguration().getMaxBarcodeCount() != null ?
|
||||||
|
taskEntry.getConfiguration().getMaxBarcodeCount() : 10);
|
||||||
|
|
||||||
|
barcodeLayout.add(minBarcodes, maxBarcodes);
|
||||||
|
|
||||||
|
minBarcodes.addValueChangeListener(ev -> {
|
||||||
|
taskEntry.getConfiguration().setMinBarcodeCount(ev.getValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
maxBarcodes.addValueChangeListener(ev -> {
|
||||||
|
taskEntry.getConfiguration().setMaxBarcodeCount(ev.getValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
configContainer.add(barcodeLayout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTodoItems(VerticalLayout todoList, TaskEntry taskEntry) {
|
||||||
|
List<String> todoItems = todoList.getChildren()
|
||||||
|
.map(component -> {
|
||||||
|
if (component instanceof HorizontalLayout) {
|
||||||
|
HorizontalLayout row = (HorizontalLayout) component;
|
||||||
|
TextField field = (TextField) row.getChildren().findFirst().orElse(null);
|
||||||
|
return field != null ? field.getValue() : null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(item -> !item.trim().isEmpty())
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
|
taskEntry.getConfiguration().setTodoItems(todoItems);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user