Erweiterungen

This commit is contained in:
2025-08-14 12:34:43 +02:00
parent 9ad857b8a7
commit 40de64c95e
6 changed files with 190 additions and 173 deletions

View File

@@ -5,6 +5,7 @@ import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.annotation.Transient;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -71,9 +72,6 @@ public class Job {
@Field("pickup_city")
private String pickupCity;
@Field("save_pickup_address")
private boolean savePickupAddress;
// Lieferadresse
@Field("delivery_company")
private String deliveryCompany;
@@ -105,9 +103,6 @@ public class Job {
@Field("delivery_city")
private String deliveryCity;
@Field("save_delivery_address")
private boolean saveDeliveryAddress;
// Digitale Abwicklung per App
@Field("digital_processing")
private boolean digitalProcessing;
@@ -126,10 +121,6 @@ public class Job {
@Field("remark")
private String remark;
// Aufgaben
@Field("tasks")
private List<String> tasks;
// Preis (netto)
@Field("price")
private BigDecimal price;

View File

@@ -0,0 +1,25 @@
package de.assecutor.votianlt.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "tasks")
public class TaskEntry {
@Id
private ObjectId id;
@Field("job_id")
private ObjectId jobId;
@Field("text")
private String text;
}

View File

@@ -3,9 +3,12 @@ package de.assecutor.votianlt.pages.add_job.service;
import de.assecutor.votianlt.model.CargoItem;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.JobStatus;
import de.assecutor.votianlt.repository.CargoItemRepository;
import de.assecutor.votianlt.model.TaskEntry;
import de.assecutor.votianlt.repository.JobRepository;
import de.assecutor.votianlt.repository.TaskRepository;
import de.assecutor.votianlt.security.SecurityService;
import de.assecutor.votianlt.repository.CargoItemRepository;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
@@ -15,22 +18,22 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class AddJobService {
private final JobRepository jobRepository;
private final CargoItemRepository cargoItemRepository;
private final JobRepository jobRepository;
private final TaskRepository taskRepository;
private final SecurityService securityService;
/**
* Speichert einen neuen Auftrag samt CargoItems (separat in cargo_items)
* Speichert einen neuen Auftrag samt CargoItems und Tasks
* @param job der Auftrag
* @param transientCargo zugehörige, noch nicht gespeicherte CargoItems aus der View
*/
public Job addJobWithCargo(Job job, List<CargoItem> transientCargo) {
public Job addJobWithCargo(Job job, List<CargoItem> transientCargo, List<TaskEntry> transientTasks) {
try {
// Metadaten setzen
LocalDateTime now = LocalDateTime.now();
@@ -46,23 +49,42 @@ public class AddJobService {
// Auftrag speichern
Job savedJob = jobRepository.save(job);
final ObjectId jobId = savedJob.getId();
boolean modified = false;
// CargoItems separat mit Referenz auf Job speichern, IDs im Job verknüpfen
if (transientCargo != null && !transientCargo.isEmpty()) {
final ObjectId jobId = savedJob.getId();
List<CargoItem> itemsWithJob = transientCargo.stream().map(ci -> {
CargoItem copy = new CargoItem();
copy.setJobId(jobId);
copy.setDescription(ci.getDescription());
copy.setQuantity(ci.getQuantity());
copy.setWeightKg(ci.getWeightKg());
copy.setLengthMm(ci.getLengthMm());
copy.setWidthMm(ci.getWidthMm());
copy.setHeightMm(ci.getHeightMm());
return copy;
}).collect(java.util.stream.Collectors.toList());
List<CargoItem> savedItems = cargoItemRepository.saveAll(itemsWithJob);
List<ObjectId> cargoIds = savedItems.stream().map(CargoItem::getId).collect(java.util.stream.Collectors.toList());
List<CargoItem> itemsWithJob = transientCargo.stream()
.filter(Objects::nonNull)
.filter(ci -> ci.getDescription() != null && !ci.getDescription().isBlank())
.map(ci -> {
CargoItem copy = new CargoItem();
copy.setJobId(jobId);
copy.setDescription(ci.getDescription());
copy.setQuantity(ci.getQuantity());
copy.setWeightKg(ci.getWeightKg());
copy.setLengthMm(ci.getLengthMm());
copy.setWidthMm(ci.getWidthMm());
copy.setHeightMm(ci.getHeightMm());
return copy;
}).toList();
var savedItems = cargoItemRepository.saveAll(itemsWithJob);
var cargoIds = savedItems.stream().map(CargoItem::getId).toList();
modified = true;
// Tasks separat speichern und referenzieren
if (transientTasks != null && !transientTasks.isEmpty()) {
var prepared = transientTasks.stream()
.filter(Objects::nonNull)
.filter(te -> te.getText() != null && !te.getText().isBlank())
.peek(te -> te.setJobId(jobId))
.toList();
var savedTasks = taskRepository.saveAll(prepared);
var taskIds = savedTasks.stream().map(de.assecutor.votianlt.model.TaskEntry::getId).toList();
modified = true;
}
}
if (modified) {
savedJob = jobRepository.save(savedJob);
}
@@ -75,36 +97,6 @@ public class AddJobService {
}
}
/**
* Speichert einen neuen Auftrag in der MongoDB
*/
public Job addJob(Job job) {
try {
// Metadaten setzen
LocalDateTime now = LocalDateTime.now();
job.setCreatedAt(now);
job.setUpdatedAt(now);
job.setStatus(JobStatus.CREATED);
job.setCreatedBy(securityService.getCurrentUsername());
// Auftragsnummer generieren, falls nicht vorhanden
if (job.getJobNumber() == null || job.getJobNumber().isEmpty()) {
job.setJobNumber(generateJobNumber());
}
// Auftrag speichern
Job savedJob = jobRepository.save(job);
log.info("Auftrag erfolgreich gespeichert: {}", savedJob.getJobNumber());
return savedJob;
} catch (Exception e) {
log.error("Fehler beim Speichern des Auftrags: {}", e.getMessage(), e);
throw new RuntimeException("Auftrag konnte nicht gespeichert werden: " + e.getMessage());
}
}
/**
* Aktualisiert einen bestehenden Auftrag
*/
@@ -206,7 +198,7 @@ public class AddJobService {
/**
* Speichert einen Auftrag als Entwurf (für automatisches Speichern)
*/
public Job saveDraft(Job job) {
public void saveDraft(Job job) {
try {
// Prüfen ob bereits ein Entwurf für diesen Benutzer existiert
String currentUser = securityService.getCurrentUsername();
@@ -215,7 +207,7 @@ public class AddJobService {
Job draftJob;
if (!existingDrafts.isEmpty()) {
// Bestehenden Entwurf aktualisieren
draftJob = existingDrafts.get(0);
draftJob = existingDrafts.getFirst();
updateJobFromForm(draftJob, job);
draftJob.setUpdatedAt(LocalDateTime.now());
} else {
@@ -236,8 +228,6 @@ public class AddJobService {
Job savedDraft = jobRepository.save(draftJob);
log.info("Entwurf automatisch gespeichert für Benutzer: {}", currentUser);
return savedDraft;
} catch (Exception e) {
log.error("Fehler beim Speichern des Entwurfs: {}", e.getMessage(), e);
throw new RuntimeException("Entwurf konnte nicht gespeichert werden: " + e.getMessage());
@@ -261,7 +251,6 @@ public class AddJobService {
existingJob.setPickupAddressAddition(formJob.getPickupAddressAddition());
existingJob.setPickupZip(formJob.getPickupZip());
existingJob.setPickupCity(formJob.getPickupCity());
existingJob.setSavePickupAddress(formJob.isSavePickupAddress());
// Delivery address
existingJob.setDeliveryCompany(formJob.getDeliveryCompany());
@@ -274,7 +263,6 @@ public class AddJobService {
existingJob.setDeliveryAddressAddition(formJob.getDeliveryAddressAddition());
existingJob.setDeliveryZip(formJob.getDeliveryZip());
existingJob.setDeliveryCity(formJob.getDeliveryCity());
existingJob.setSaveDeliveryAddress(formJob.isSaveDeliveryAddress());
// Digital processing
existingJob.setDigitalProcessing(formJob.isDigitalProcessing());
@@ -284,7 +272,6 @@ public class AddJobService {
existingJob.setPickupDate(formJob.getPickupDate());
existingJob.setDeliveryDate(formJob.getDeliveryDate());
existingJob.setRemark(formJob.getRemark());
existingJob.setTasks(formJob.getTasks());
existingJob.setPrice(formJob.getPrice());
}
@@ -293,15 +280,6 @@ public class AddJobService {
*/
public Optional<Job> findCurrentDraft(String username) {
List<Job> drafts = jobRepository.findByCreatedByAndIsDraftTrue(username);
return drafts.isEmpty() ? Optional.empty() : Optional.of(drafts.get(0));
}
/**
* Löscht alle Entwürfe eines Benutzers
*/
public void deleteUserDrafts(String username) {
List<Job> drafts = jobRepository.findByCreatedByAndIsDraftTrue(username);
jobRepository.deleteAll(drafts);
log.info("Entwürfe für Benutzer {} gelöscht", username);
return drafts.isEmpty() ? Optional.empty() : Optional.of(drafts.getFirst());
}
}

View File

@@ -33,11 +33,16 @@ import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.theme.lumo.LumoUtility;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.TaskEntry;
import de.assecutor.votianlt.pages.add_job.service.AddJobService;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
import jakarta.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j;
import de.assecutor.votianlt.model.CargoItem;
import java.util.*;
import java.util.Objects;
import de.assecutor.votianlt.model.TaskEntry;
import java.util.Optional;
@Route(value = "add_job", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@@ -100,11 +105,16 @@ public class AddJobView extends Main {
// Submit button
private Button submitButton;
// Transient transfer list for cargo items (not part of Job entity anymore)
private java.util.List<de.assecutor.votianlt.model.CargoItem> jobTransientCargo;
// Backing list for cargo items to mirror UI rows
private final List<CargoItem> cargoItemsState = new ArrayList<>();
// Stage sections for drag and drop
// Backing list for tasks to mirror UI rows
private final List<TaskEntry> tasksState = new ArrayList<>();
// Dynamic lists and additional controls
// Cargo section UI refs for error highlighting
private VerticalLayout cargoAreaContainer;
private Span cargoError;
private VerticalLayout cargoList;
private VerticalLayout tasksList;
private TextArea remarkArea;
@@ -647,13 +657,11 @@ public class AddJobView extends Main {
binder.bind(pickupSalutation, Job::getPickupSalutation, Job::setPickupSalutation);
binder.bind(pickupPhone, Job::getPickupPhone, Job::setPickupPhone);
binder.bind(pickupAddressAddition, Job::getPickupAddressAddition, Job::setPickupAddressAddition);
binder.bind(savePickupAddress, Job::isSavePickupAddress, Job::setSavePickupAddress);
binder.bind(deliveryCompany, Job::getDeliveryCompany, Job::setDeliveryCompany);
binder.bind(deliverySalutation, Job::getDeliverySalutation, Job::setDeliverySalutation);
binder.bind(deliveryPhone, Job::getDeliveryPhone, Job::setDeliveryPhone);
binder.bind(deliveryAddressAddition, Job::getDeliveryAddressAddition, Job::setDeliveryAddressAddition);
binder.bind(saveDeliveryAddress, Job::isSaveDeliveryAddress, Job::setSaveDeliveryAddress);
binder.bind(digitalProcessing, Job::isDigitalProcessing, Job::setDigitalProcessing);
binder.bind(appUser, Job::getAppUser, Job::setAppUser);
@@ -800,54 +808,33 @@ public class AddJobView extends Main {
job.setPickupDate(pickupDate.getValue());
job.setDeliveryDate(deliveryDate.getValue());
if (remarkArea != null) job.setRemark(remarkArea.getValue());
if (tasksList != null) {
java.util.List<String> tasks = new java.util.ArrayList<>();
tasksList.getChildren().forEach(comp -> {
if (comp instanceof com.vaadin.flow.component.orderedlayout.HorizontalLayout row) {
row.getChildren().filter(c -> c instanceof TextField).forEach(tf -> {
String v = ((TextField) tf).getValue();
if (v != null && !v.trim().isEmpty()) tasks.add(v.trim());
});
}
});
job.setTasks(tasks);
}
if (cargoList != null) {
java.util.List<de.assecutor.votianlt.model.CargoItem> items = new java.util.ArrayList<>();
cargoList.getChildren().forEach(comp -> {
if (comp instanceof com.vaadin.flow.component.orderedlayout.HorizontalLayout row) {
String desc = null; Integer qty = null; Double weight = null, len = null, wid = null, hei = null;
for (com.vaadin.flow.component.Component c : row.getChildren().toList()) {
if (c instanceof TextField tf && tf.getLabel() != null && tf.getLabel().contains("Beschreibung")) desc = tf.getValue();
if (c instanceof IntegerField ifld) qty = ifld.getValue();
if (c instanceof NumberField nf) {
String label = nf.getLabel();
if (label != null) {
switch (label) {
case "Gewicht" -> weight = nf.getValue();
case "Länge" -> len = nf.getValue();
case "Breite" -> wid = nf.getValue();
case "Höhe" -> hei = nf.getValue();
}
}
}
}
if (desc != null || qty != null || weight != null || len != null || wid != null || hei != null) {
de.assecutor.votianlt.model.CargoItem ci = new de.assecutor.votianlt.model.CargoItem();
ci.setDescription(desc); ci.setQuantity(qty); ci.setWeightKg(weight);
ci.setLengthMm(len); ci.setWidthMm(wid); ci.setHeightMm(hei);
items.add(ci);
}
}
});
// temporär im Job-Objekt als Transfertyp beilegen (über transient Helper)
jobTransientCargo = items;
}
// Validate all required fields using the binder
if (binder.writeBeanIfValid(job)) {
// All validations passed, save the job with cargo items
Job savedJob = addJobService.addJobWithCargo(job, jobTransientCargo);
// Ensure at least one cargo item is provided (tasks may be empty)
// Definition: Ein Cargo-Item gilt nur als gefüllt, wenn eine Beschreibung vorhanden ist
List<CargoItem> cargoFilled = cargoItemsState.stream()
.filter(Objects::nonNull)
.filter(ci -> ci.getDescription() != null && !ci.getDescription().isBlank())
.toList();
if (cargoFilled.isEmpty()) {
Notification errorNotification = Notification.show(
"Bitte fügen Sie mindestens eine Ladungszeile hinzu.");
errorNotification.setDuration(5000);
return;
}
// toggle cargo error highlight
boolean hasCargo = !cargoFilled.isEmpty();
cargoError.setVisible(!hasCargo);
if (!hasCargo) {
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-error-color-50pct)");
} else {
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
}
// All validations passed, save the job with cargo items and tasks (tasks may be empty)
Job savedJob = addJobService.addJobWithCargo(job, cargoFilled, tasksState);
// Erfolgsmeldung anzeigen
Notification successNotification = Notification.show(
@@ -865,6 +852,9 @@ public class AddJobView extends Main {
} catch (Exception e) {
// Other errors
// Reset cargo error
if (cargoError != null) cargoError.setVisible(false);
if (cargoAreaContainer != null) cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
Notification errorNotification = Notification.show(
"Fehler beim Erstellen des Auftrags: " + e.getMessage());
errorNotification.setDuration(5000);
@@ -872,11 +862,19 @@ public class AddJobView extends Main {
}
/**
cargoItemsState.clear();
cargoList.removeAll();
* Setzt alle Formularfelder zurück
*/
private void clearForm() {
// Reset cargo state and UI
cargoItemsState.clear();
if (cargoList != null) cargoList.removeAll();
// Reset binder to clear validation state
binder.readBean(new Job());
// Reset tasks state and UI
tasksState.clear();
if (tasksList != null) tasksList.removeAll();
// Customer selection
customerSelection.clear();
@@ -937,7 +935,6 @@ public class AddJobView extends Main {
job.setPickupAddressAddition(pickupAddressAddition.getValue());
job.setPickupZip(pickupZip.getValue());
job.setPickupCity(pickupCity.getValue());
job.setSavePickupAddress(savePickupAddress.getValue());
// Delivery address
job.setDeliveryCompany(deliveryCompany.getValue());
@@ -950,7 +947,6 @@ public class AddJobView extends Main {
job.setDeliveryAddressAddition(deliveryAddressAddition.getValue());
job.setDeliveryZip(deliveryZip.getValue());
job.setDeliveryCity(deliveryCity.getValue());
job.setSaveDeliveryAddress(saveDeliveryAddress.getValue());
// Digital processing
job.setDigitalProcessing(digitalProcessing.getValue());
@@ -1015,28 +1011,32 @@ public class AddJobView extends Main {
wrapper.setWidthFull();
wrapper.setSpacing(true);
VerticalLayout cargoArea = new VerticalLayout();
cargoArea.setWidthFull();
cargoArea.setSpacing(true);
cargoArea.getStyle().set("background", "var(--lumo-base-color)");
cargoArea.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
cargoArea.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
cargoArea.getStyle().set("padding", "var(--lumo-space-m)");
cargoAreaContainer = new VerticalLayout();
cargoAreaContainer.setWidthFull();
cargoAreaContainer.setSpacing(true);
cargoAreaContainer.getStyle().set("background", "var(--lumo-base-color)");
cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
cargoAreaContainer.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
cargoAreaContainer.getStyle().set("padding", "var(--lumo-space-m)");
wrapper.add(new H3("Ladung"));
H3 cargoTitle = new H3("Ladung");
cargoError = new Span("Bitte fügen Sie mindestens eine Ladungszeile hinzu.");
cargoError.getStyle().set("color", "var(--lumo-error-text-color)");
cargoError.getStyle().set("font-size", "var(--lumo-font-size-s)");
cargoError.setVisible(false);
wrapper.add(cargoTitle);
cargoList = new VerticalLayout();
cargoList.setPadding(false);
cargoList.setSpacing(true);
cargoArea.add(cargoList);
cargoAreaContainer.add(cargoError, cargoList);
java.util.function.BiConsumer<String, java.util.function.Consumer<HorizontalLayout>> addCargoRow = (iconName, afterCreate) -> {
HorizontalLayout row = new HorizontalLayout();
row.setWidthFull();
row.setAlignItems(FlexComponent.Alignment.END);
ComboBox<String> desc = new ComboBox<>("Beschreibung");
desc.setItems("Europalette", "Einwegpalette", "Düsseldorfer-Palette", "Gitterboxpalette", "Gitterwagen", "Paket");
desc.setAllowCustomValue(true);
@@ -1064,10 +1064,43 @@ public class AddJobView extends Main {
Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
remove.addClickListener(e -> cargoList.remove(row));
remove.addClickListener(e -> {
int idx = cargoList.getChildren().toList().indexOf(row);
if (idx >= 0 && idx < cargoItemsState.size()) {
cargoItemsState.remove(idx);
}
cargoList.remove(row);
});
row.add(desc, qty, weight, len, wid, hei, remove);
cargoList.add(row);
// Ensure backing list is in sync: add new item and bind change listeners
CargoItem item = new CargoItem();
cargoItemsState.add(item);
// Pre-fill current input values into backing item
item.setDescription(desc.getValue());
item.setQuantity(qty.getValue());
item.setWeightKg(weight.getValue());
item.setLengthMm(len.getValue());
// Initialize from current inputs
item.setDescription(desc.getValue());
item.setQuantity(qty.getValue());
item.setWeightKg(weight.getValue());
item.setLengthMm(len.getValue());
item.setWidthMm(wid.getValue());
item.setHeightMm(hei.getValue());
item.setWidthMm(wid.getValue());
item.setHeightMm(hei.getValue());
desc.addValueChangeListener(ev -> item.setDescription(ev.getValue()));
qty.addValueChangeListener(ev -> item.setQuantity(ev.getValue()));
weight.addValueChangeListener(ev -> item.setWeightKg(ev.getValue()));
len.addValueChangeListener(ev -> item.setLengthMm(ev.getValue()));
wid.addValueChangeListener(ev -> item.setWidthMm(ev.getValue()));
hei.addValueChangeListener(ev -> item.setHeightMm(ev.getValue()));
if (afterCreate != null) afterCreate.accept(row);
};
@@ -1075,42 +1108,10 @@ public class AddJobView extends Main {
addCargoRow.accept("paket", r -> {});
addCargoRow.accept("", r -> {});
wrapper.add(cargoArea);
wrapper.add(cargoAreaContainer);
return wrapper;
}
private void populateFromJob(Job job) {
// Pickup address
if (job.getPickupCompany() != null) pickupCompany.setValue(job.getPickupCompany());
if (job.getPickupSalutation() != null) pickupSalutation.setValue(job.getPickupSalutation());
if (job.getPickupFirstName() != null) pickupFirstName.setValue(job.getPickupFirstName());
if (job.getPickupLastName() != null) pickupLastName.setValue(job.getPickupLastName());
if (job.getPickupPhone() != null) pickupPhone.setValue(job.getPickupPhone());
if (job.getPickupStreet() != null) pickupStreet.setValue(job.getPickupStreet());
if (job.getPickupHouseNumber() != null) pickupHouseNumber.setValue(job.getPickupHouseNumber());
if (job.getPickupAddressAddition() != null) pickupAddressAddition.setValue(job.getPickupAddressAddition());
if (job.getPickupZip() != null) pickupZip.setValue(job.getPickupZip());
if (job.getPickupCity() != null) pickupCity.setValue(job.getPickupCity());
savePickupAddress.setValue(job.isSavePickupAddress());
// Delivery address
if (job.getDeliveryCompany() != null) deliveryCompany.setValue(job.getDeliveryCompany());
if (job.getDeliverySalutation() != null) deliverySalutation.setValue(job.getDeliverySalutation());
if (job.getDeliveryFirstName() != null) deliveryFirstName.setValue(job.getDeliveryFirstName());
if (job.getDeliveryLastName() != null) deliveryLastName.setValue(job.getDeliveryLastName());
if (job.getDeliveryPhone() != null) deliveryPhone.setValue(job.getDeliveryPhone());
if (job.getDeliveryStreet() != null) deliveryStreet.setValue(job.getDeliveryStreet());
if (job.getDeliveryHouseNumber() != null) deliveryHouseNumber.setValue(job.getDeliveryHouseNumber());
if (job.getDeliveryAddressAddition() != null) deliveryAddressAddition.setValue(job.getDeliveryAddressAddition());
if (job.getDeliveryZip() != null) deliveryZip.setValue(job.getDeliveryZip());
if (job.getDeliveryCity() != null) deliveryCity.setValue(job.getDeliveryCity());
saveDeliveryAddress.setValue(job.isSaveDeliveryAddress());
// Digital processing
digitalProcessing.setValue(job.isDigitalProcessing());
if (job.getAppUser() != null) appUser.setValue(job.getAppUser());
}
private Component createTasksAndNotesSection() {
VerticalLayout wrapper = new VerticalLayout();
wrapper.setWidthFull();
@@ -1144,11 +1145,21 @@ public class AddJobView extends Main {
Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
remove.addClickListener(e -> tasksList.remove(row));
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

View File

@@ -0,0 +1,12 @@
package de.assecutor.votianlt.repository;
import de.assecutor.votianlt.model.TaskEntry;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface TaskRepository extends MongoRepository<TaskEntry, ObjectId> {
List<TaskEntry> findByJobId(ObjectId jobId);
}