Erweiterungen
This commit is contained in:
37
src/main/java/de/assecutor/votianlt/model/TaskTemplate.java
Normal file
37
src/main/java/de/assecutor/votianlt/model/TaskTemplate.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package de.assecutor.votianlt.model;
|
||||||
|
|
||||||
|
import de.assecutor.votianlt.model.task.BaseTask;
|
||||||
|
import lombok.Data;
|
||||||
|
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.index.Indexed;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Document(collection = "task_templates")
|
||||||
|
public class TaskTemplate {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private ObjectId id;
|
||||||
|
|
||||||
|
@Indexed
|
||||||
|
private ObjectId userId;
|
||||||
|
|
||||||
|
private String templateName;
|
||||||
|
private List<BaseTask> tasks;
|
||||||
|
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public TaskTemplate() {
|
||||||
|
this.createdAt = LocalDateTime.now();
|
||||||
|
this.updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTimestamp() {
|
||||||
|
this.updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package de.assecutor.votianlt.pages.service;
|
||||||
|
|
||||||
|
import de.assecutor.votianlt.model.TaskTemplate;
|
||||||
|
import de.assecutor.votianlt.model.task.BaseTask;
|
||||||
|
import de.assecutor.votianlt.repository.TaskTemplateRepository;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TaskTemplateService {
|
||||||
|
|
||||||
|
private final TaskTemplateRepository taskTemplateRepository;
|
||||||
|
|
||||||
|
public TaskTemplateService(TaskTemplateRepository taskTemplateRepository) {
|
||||||
|
this.taskTemplateRepository = taskTemplateRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TaskTemplate> findByUserId(ObjectId userId) {
|
||||||
|
return taskTemplateRepository.findByUserIdOrderByTemplateNameAsc(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<TaskTemplate> findByUserIdAndTemplateName(ObjectId userId, String templateName) {
|
||||||
|
return taskTemplateRepository.findByUserIdAndTemplateName(userId, templateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskTemplate save(TaskTemplate taskTemplate) {
|
||||||
|
taskTemplate.updateTimestamp();
|
||||||
|
return taskTemplateRepository.save(taskTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskTemplate createTemplate(ObjectId userId, String templateName, List<BaseTask> tasks) {
|
||||||
|
// Check if template with same name already exists for this user
|
||||||
|
Optional<TaskTemplate> existing = findByUserIdAndTemplateName(userId, templateName);
|
||||||
|
if (existing.isPresent()) {
|
||||||
|
throw new RuntimeException("Template mit dem Namen '" + templateName + "' existiert bereits");
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskTemplate template = new TaskTemplate();
|
||||||
|
template.setUserId(userId);
|
||||||
|
template.setTemplateName(templateName);
|
||||||
|
template.setTasks(tasks);
|
||||||
|
|
||||||
|
return save(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteByUserIdAndTemplateName(ObjectId userId, String templateName) {
|
||||||
|
taskTemplateRepository.deleteByUserIdAndTemplateName(userId, templateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean templateExists(ObjectId userId, String templateName) {
|
||||||
|
return findByUserIdAndTemplateName(userId, templateName).isPresent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import com.vaadin.flow.component.button.Button;
|
|||||||
import com.vaadin.flow.component.button.ButtonVariant;
|
import com.vaadin.flow.component.button.ButtonVariant;
|
||||||
import com.vaadin.flow.component.checkbox.Checkbox;
|
import com.vaadin.flow.component.checkbox.Checkbox;
|
||||||
import com.vaadin.flow.component.combobox.ComboBox;
|
import com.vaadin.flow.component.combobox.ComboBox;
|
||||||
|
import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
|
||||||
|
import com.vaadin.flow.component.dialog.Dialog;
|
||||||
|
|
||||||
import com.vaadin.flow.component.datepicker.DatePicker;
|
import com.vaadin.flow.component.datepicker.DatePicker;
|
||||||
import com.vaadin.flow.component.html.H2;
|
import com.vaadin.flow.component.html.H2;
|
||||||
@@ -44,6 +46,9 @@ import de.assecutor.votianlt.pages.service.AddCustomerService;
|
|||||||
import de.assecutor.votianlt.model.Customer;
|
import de.assecutor.votianlt.model.Customer;
|
||||||
import de.assecutor.votianlt.pages.service.AppUserService;
|
import de.assecutor.votianlt.pages.service.AppUserService;
|
||||||
import de.assecutor.votianlt.model.AppUser;
|
import de.assecutor.votianlt.model.AppUser;
|
||||||
|
import de.assecutor.votianlt.pages.service.TaskTemplateService;
|
||||||
|
import de.assecutor.votianlt.model.TaskTemplate;
|
||||||
|
import de.assecutor.votianlt.security.SecurityService;
|
||||||
|
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -63,6 +68,8 @@ public class AddJobView extends Main {
|
|||||||
private final CustomerService customerService;
|
private final CustomerService customerService;
|
||||||
private final AddCustomerService addCustomerService;
|
private final AddCustomerService addCustomerService;
|
||||||
private final AppUserService appUserService;
|
private final AppUserService appUserService;
|
||||||
|
private final TaskTemplateService taskTemplateService;
|
||||||
|
private final SecurityService securityService;
|
||||||
|
|
||||||
// Customer selection
|
// Customer selection
|
||||||
private ComboBox<String> customerSelection;
|
private ComboBox<String> customerSelection;
|
||||||
@@ -138,11 +145,14 @@ public class AddJobView extends Main {
|
|||||||
private List<AppUser> availableAppUsers;
|
private List<AppUser> availableAppUsers;
|
||||||
|
|
||||||
public AddJobView(AddJobService addJobService, AddCustomerService addCustomerService,
|
public AddJobView(AddJobService addJobService, AddCustomerService addCustomerService,
|
||||||
CustomerService customerService, AppUserService appUserService) {
|
CustomerService customerService, AppUserService appUserService,
|
||||||
|
TaskTemplateService taskTemplateService, SecurityService securityService) {
|
||||||
this.addJobService = addJobService;
|
this.addJobService = addJobService;
|
||||||
this.addCustomerService = addCustomerService;
|
this.addCustomerService = addCustomerService;
|
||||||
this.customerService = customerService;
|
this.customerService = customerService;
|
||||||
this.appUserService = appUserService;
|
this.appUserService = appUserService;
|
||||||
|
this.taskTemplateService = taskTemplateService;
|
||||||
|
this.securityService = securityService;
|
||||||
initializeComponents();
|
initializeComponents();
|
||||||
setupLayout();
|
setupLayout();
|
||||||
setupValidation();
|
setupValidation();
|
||||||
@@ -1295,10 +1305,37 @@ public class AddJobView extends Main {
|
|||||||
content.setSpacing(true);
|
content.setSpacing(true);
|
||||||
content.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
|
content.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
|
||||||
|
|
||||||
// Aufgabentitel
|
// Aufgabentitel mit Template-Auswahl
|
||||||
H3 tasksTitle = new H3("Zu quittierende Aufgaben");
|
H3 tasksTitle = new H3("Zu quittierende Aufgaben");
|
||||||
tasksTitle.getStyle().set("margin", "0");
|
tasksTitle.getStyle().set("margin", "0");
|
||||||
content.add(tasksTitle);
|
|
||||||
|
ComboBox<TaskTemplate> templateComboBox = new ComboBox<>();
|
||||||
|
templateComboBox.setPlaceholder("Template auswählen...");
|
||||||
|
templateComboBox.setItemLabelGenerator(TaskTemplate::getTemplateName);
|
||||||
|
templateComboBox.setClearButtonVisible(true);
|
||||||
|
// Breite auf verbleibenden Platz einstellen
|
||||||
|
templateComboBox.setWidthFull();
|
||||||
|
|
||||||
|
// Load templates for current user
|
||||||
|
loadTemplatesIntoComboBox(templateComboBox);
|
||||||
|
|
||||||
|
// Handle template selection
|
||||||
|
templateComboBox.addValueChangeListener(e -> {
|
||||||
|
if (e.getValue() != null) {
|
||||||
|
loadTasksFromTemplate(e.getValue(), templateComboBox);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Icon-Button zum Speichern als Template
|
||||||
|
Button saveAsTemplateBtn = new Button(new Icon(VaadinIcon.BOOKMARK));
|
||||||
|
saveAsTemplateBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||||
|
saveAsTemplateBtn.setTooltipText("Aufgaben als Template speichern");
|
||||||
|
saveAsTemplateBtn.addClickListener(e -> saveTasksAsTemplate());
|
||||||
|
|
||||||
|
HorizontalLayout titleWithTemplate = new HorizontalLayout(tasksTitle, templateComboBox, saveAsTemplateBtn);
|
||||||
|
titleWithTemplate.setAlignItems(FlexComponent.Alignment.CENTER);
|
||||||
|
titleWithTemplate.setSpacing(true);
|
||||||
|
content.add(titleWithTemplate);
|
||||||
|
|
||||||
// Dynamische Aufgabenliste
|
// Dynamische Aufgabenliste
|
||||||
tasksList = new VerticalLayout();
|
tasksList = new VerticalLayout();
|
||||||
@@ -1664,8 +1701,42 @@ public class AddJobView extends Main {
|
|||||||
addTodoBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
addTodoBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||||
addTodoBtn.addClickListener(e -> addTodoItem.accept(null));
|
addTodoBtn.addClickListener(e -> addTodoItem.accept(null));
|
||||||
|
|
||||||
// Add initial todo item
|
// Load existing todo items from the task, or add one empty item if none exist
|
||||||
|
if (task instanceof TodoListTask) {
|
||||||
|
TodoListTask todoTask = (TodoListTask) task;
|
||||||
|
if (todoTask.getTodoItems() != null && !todoTask.getTodoItems().isEmpty()) {
|
||||||
|
// Create UI rows for existing todo items
|
||||||
|
for (String todoText : todoTask.getTodoItems()) {
|
||||||
|
HorizontalLayout todoRow = new HorizontalLayout();
|
||||||
|
todoRow.setWidthFull();
|
||||||
|
todoRow.setAlignItems(FlexComponent.Alignment.END);
|
||||||
|
|
||||||
|
TextField todoField = new TextField();
|
||||||
|
todoField.setPlaceholder("To-Do Punkt");
|
||||||
|
todoField.setWidth("100%");
|
||||||
|
todoField.setValue(todoText != null ? todoText : ""); // Set the saved text
|
||||||
|
|
||||||
|
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, task);
|
||||||
|
});
|
||||||
|
|
||||||
|
todoRow.add(todoField, removeTodo);
|
||||||
|
todoRow.setFlexGrow(1, todoField);
|
||||||
|
todoList.add(todoRow);
|
||||||
|
|
||||||
|
todoField.addValueChangeListener(ev -> updateTodoItems(todoList, task));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add initial empty todo item if no existing items
|
||||||
addTodoItem.accept(null);
|
addTodoItem.accept(null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add initial empty todo item for new tasks
|
||||||
|
addTodoItem.accept(null);
|
||||||
|
}
|
||||||
|
|
||||||
todoContainer.add(todoList, addTodoBtn);
|
todoContainer.add(todoList, addTodoBtn);
|
||||||
configContainer.add(todoContainer);
|
configContainer.add(todoContainer);
|
||||||
@@ -1746,4 +1817,328 @@ public class AddJobView extends Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Speichert die aktuell konfigurierten Aufgaben als Template
|
||||||
|
*/
|
||||||
|
private void saveTasksAsTemplate() {
|
||||||
|
try {
|
||||||
|
// Check if there are any tasks to save
|
||||||
|
if (tasksState.isEmpty()) {
|
||||||
|
Notification.show("Keine Aufgaben zum Speichern vorhanden", 3000, Notification.Position.BOTTOM_END);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create dialog for template name input
|
||||||
|
Dialog dialog = new Dialog();
|
||||||
|
dialog.setHeaderTitle("Template speichern");
|
||||||
|
dialog.setWidth("400px");
|
||||||
|
|
||||||
|
VerticalLayout dialogLayout = new VerticalLayout();
|
||||||
|
dialogLayout.setPadding(false);
|
||||||
|
dialogLayout.setSpacing(true);
|
||||||
|
|
||||||
|
TextField templateNameField = new TextField("Template-Name");
|
||||||
|
templateNameField.setPlaceholder("Geben Sie einen Namen für das Template ein");
|
||||||
|
templateNameField.setWidthFull();
|
||||||
|
templateNameField.setRequiredIndicatorVisible(true);
|
||||||
|
|
||||||
|
Button saveButton = new Button("Speichern");
|
||||||
|
saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||||
|
saveButton.addClickListener(e -> {
|
||||||
|
String templateName = templateNameField.getValue();
|
||||||
|
if (templateName == null || templateName.trim().isEmpty()) {
|
||||||
|
Notification.show("Bitte geben Sie einen Template-Namen ein", 3000, Notification.Position.BOTTOM_END);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create deep copies of current tasks
|
||||||
|
List<BaseTask> tasksCopy = new ArrayList<>();
|
||||||
|
for (BaseTask task : tasksState) {
|
||||||
|
// Create a copy of each task to avoid reference issues
|
||||||
|
BaseTask taskCopy = createTaskCopy(task);
|
||||||
|
tasksCopy.add(taskCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save template with task type information and specific data
|
||||||
|
taskTemplateService.createTemplate(
|
||||||
|
securityService.getCurrentDatabaseUser().getId(),
|
||||||
|
templateName.trim(),
|
||||||
|
tasksCopy
|
||||||
|
);
|
||||||
|
|
||||||
|
dialog.close();
|
||||||
|
Notification.show("Template '" + templateName + "' erfolgreich gespeichert", 3000, Notification.Position.BOTTOM_END);
|
||||||
|
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
Notification.show(ex.getMessage(), 4000, Notification.Position.MIDDLE);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Error saving task template", ex);
|
||||||
|
Notification.show("Fehler beim Speichern des Templates: " + ex.getMessage(), 4000, Notification.Position.MIDDLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button cancelButton = new Button("Abbrechen");
|
||||||
|
cancelButton.addClickListener(e -> dialog.close());
|
||||||
|
|
||||||
|
HorizontalLayout buttonLayout = new HorizontalLayout(cancelButton, saveButton);
|
||||||
|
buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
|
||||||
|
|
||||||
|
dialogLayout.add(templateNameField, buttonLayout);
|
||||||
|
dialog.add(dialogLayout);
|
||||||
|
dialog.open();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error opening save template dialog", e);
|
||||||
|
Notification.show("Fehler beim Öffnen des Dialogs: " + e.getMessage(), 4000, Notification.Position.MIDDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a deep copy of a task to avoid reference issues in templates
|
||||||
|
* Saves all task-specific data including type and specific properties
|
||||||
|
*/
|
||||||
|
private BaseTask createTaskCopy(BaseTask original) {
|
||||||
|
BaseTask copy = null;
|
||||||
|
|
||||||
|
if (original instanceof ConfirmationTask) {
|
||||||
|
ConfirmationTask origTask = (ConfirmationTask) original;
|
||||||
|
copy = new ConfirmationTask();
|
||||||
|
// Copy all specific data for ConfirmationTask
|
||||||
|
if (origTask.getButtonText() != null) {
|
||||||
|
((ConfirmationTask) copy).setButtonText(origTask.getButtonText());
|
||||||
|
}
|
||||||
|
} else if (original instanceof SignatureTask) {
|
||||||
|
// SignatureTask has no specific data beyond the base task
|
||||||
|
copy = new SignatureTask();
|
||||||
|
} else if (original instanceof TodoListTask) {
|
||||||
|
TodoListTask origTask = (TodoListTask) original;
|
||||||
|
copy = new TodoListTask();
|
||||||
|
// Copy all todo items
|
||||||
|
if (origTask.getTodoItems() != null) {
|
||||||
|
((TodoListTask) copy).setTodoItems(new ArrayList<>(origTask.getTodoItems()));
|
||||||
|
}
|
||||||
|
} else if (original instanceof PhotoTask) {
|
||||||
|
PhotoTask origTask = (PhotoTask) original;
|
||||||
|
// Copy with all photo-specific parameters
|
||||||
|
copy = new PhotoTask(
|
||||||
|
origTask.getMinPhotoCount() != null ? origTask.getMinPhotoCount() : 1,
|
||||||
|
origTask.getMaxPhotoCount() != null ? origTask.getMaxPhotoCount() : 10
|
||||||
|
);
|
||||||
|
} else if (original instanceof BarcodeTask) {
|
||||||
|
BarcodeTask origTask = (BarcodeTask) original;
|
||||||
|
// Copy with all barcode-specific parameters
|
||||||
|
copy = new BarcodeTask(
|
||||||
|
origTask.getMinBarcodeCount() != null ? origTask.getMinBarcodeCount() : 1,
|
||||||
|
origTask.getMaxBarcodeCount() != null ? origTask.getMaxBarcodeCount() : 10
|
||||||
|
);
|
||||||
|
} else if (original instanceof CommentTask) {
|
||||||
|
CommentTask origTask = (CommentTask) original;
|
||||||
|
// Copy with all comment-specific parameters
|
||||||
|
copy = new CommentTask(
|
||||||
|
origTask.getCommentText() != null ? origTask.getCommentText() : "",
|
||||||
|
origTask.isRequired()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy != null) {
|
||||||
|
// Copy all base task properties
|
||||||
|
copy.setTaskOrder(original.getTaskOrder() != null ? original.getTaskOrder() : 0);
|
||||||
|
copy.setCompleted(original.isCompleted());
|
||||||
|
copy.setCompletedAt(original.getCompletedAt());
|
||||||
|
copy.setCompletedBy(original.getCompletedBy());
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads available templates into the ComboBox
|
||||||
|
*/
|
||||||
|
private void loadTemplatesIntoComboBox(ComboBox<TaskTemplate> templateComboBox) {
|
||||||
|
try {
|
||||||
|
List<TaskTemplate> templates = taskTemplateService.findByUserId(
|
||||||
|
securityService.getCurrentDatabaseUser().getId()
|
||||||
|
);
|
||||||
|
templateComboBox.setItems(templates);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error loading templates", e);
|
||||||
|
Notification.show("Fehler beim Laden der Templates: " + e.getMessage(), 4000, Notification.Position.MIDDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads tasks from selected template with confirmation dialog
|
||||||
|
*/
|
||||||
|
private void loadTasksFromTemplate(TaskTemplate template, ComboBox<TaskTemplate> templateComboBox) {
|
||||||
|
ConfirmDialog confirmDialog = new ConfirmDialog();
|
||||||
|
confirmDialog.setHeader("Template laden");
|
||||||
|
confirmDialog.setText("Möchten Sie wirklich das Template '" + template.getTemplateName() +
|
||||||
|
"' laden? Alle aktuellen Aufgaben werden ersetzt.");
|
||||||
|
confirmDialog.setCancelable(true);
|
||||||
|
confirmDialog.setCancelText("Abbrechen");
|
||||||
|
confirmDialog.setConfirmText("Laden");
|
||||||
|
confirmDialog.setConfirmButtonTheme("primary");
|
||||||
|
|
||||||
|
confirmDialog.addConfirmListener(e -> {
|
||||||
|
try {
|
||||||
|
// Clear current tasks
|
||||||
|
tasksState.clear();
|
||||||
|
tasksList.removeAll();
|
||||||
|
|
||||||
|
// Add tasks from template
|
||||||
|
if (template.getTasks() != null) {
|
||||||
|
for (BaseTask templateTask : template.getTasks()) {
|
||||||
|
BaseTask taskCopy = createTaskCopy(templateTask);
|
||||||
|
if (taskCopy != null) {
|
||||||
|
tasksState.add(taskCopy);
|
||||||
|
createTaskRowFromTask(taskCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the combobox selection
|
||||||
|
templateComboBox.clear();
|
||||||
|
|
||||||
|
Notification.show("Template '" + template.getTemplateName() + "' erfolgreich geladen",
|
||||||
|
3000, Notification.Position.BOTTOM_END);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Error loading template tasks", ex);
|
||||||
|
Notification.show("Fehler beim Laden des Templates: " + ex.getMessage(),
|
||||||
|
4000, Notification.Position.MIDDLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
confirmDialog.addCancelListener(e -> {
|
||||||
|
// Clear the combobox selection if user cancels
|
||||||
|
templateComboBox.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
confirmDialog.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a task row from an existing task (used when loading templates)
|
||||||
|
* This creates a UI row and populates it with the task's specific data
|
||||||
|
*/
|
||||||
|
private void createTaskRowFromTask(BaseTask task) {
|
||||||
|
// Don't call createTaskRow() directly, as it would create a default ConfirmationTask
|
||||||
|
// Instead, create the UI components and set them up with the loaded task
|
||||||
|
|
||||||
|
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<TaskType> taskTypeCombo = new ComboBox<>("Aufgabentyp");
|
||||||
|
taskTypeCombo.setItems(TaskType.values());
|
||||||
|
taskTypeCombo.setItemLabelGenerator(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);
|
||||||
|
reorderTasksAfterDeletion();
|
||||||
|
}
|
||||||
|
tasksList.remove(taskContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
taskContainer.add(taskTypeCombo, configContainer);
|
||||||
|
taskContainer.add(deleteXButton);
|
||||||
|
|
||||||
|
// The task is already in tasksState from loadTasksFromTemplate
|
||||||
|
// Find the index and use it for the UI
|
||||||
|
int taskIndex = tasksState.size() - 1; // This should be the last added task
|
||||||
|
final BaseTask[] currentTask = { task };
|
||||||
|
|
||||||
|
// Set up the value change listener for the combo box
|
||||||
|
taskTypeCombo.addValueChangeListener(ev -> {
|
||||||
|
TaskType selectedType = ev.getValue();
|
||||||
|
if (selectedType != null) {
|
||||||
|
BaseTask newTask = createTaskByType(selectedType);
|
||||||
|
BaseTask oldTask = currentTask[0];
|
||||||
|
|
||||||
|
newTask.setCompleted(oldTask.isCompleted());
|
||||||
|
newTask.setCompletedAt(oldTask.getCompletedAt());
|
||||||
|
newTask.setCompletedBy(oldTask.getCompletedBy());
|
||||||
|
|
||||||
|
// Preserve task-specific properties
|
||||||
|
switch (oldTask) {
|
||||||
|
case ConfirmationTask oldConfirmationTask when newTask instanceof ConfirmationTask newConfirmationTask ->
|
||||||
|
newConfirmationTask.setButtonText(oldConfirmationTask.getButtonText());
|
||||||
|
case TodoListTask oldTodoTask when newTask instanceof TodoListTask newTodoTask ->
|
||||||
|
newTodoTask.setTodoItems(oldTodoTask.getTodoItems());
|
||||||
|
case PhotoTask oldPhotoTask when newTask instanceof PhotoTask newPhotoTask -> {
|
||||||
|
newPhotoTask.setMinPhotoCount(oldPhotoTask.getMinPhotoCount());
|
||||||
|
newPhotoTask.setMaxPhotoCount(oldPhotoTask.getMaxPhotoCount());
|
||||||
|
}
|
||||||
|
case BarcodeTask oldBarcodeTask when newTask instanceof BarcodeTask newBarcodeTask -> {
|
||||||
|
newBarcodeTask.setMinBarcodeCount(oldBarcodeTask.getMinBarcodeCount());
|
||||||
|
newBarcodeTask.setMaxBarcodeCount(oldBarcodeTask.getMaxBarcodeCount());
|
||||||
|
}
|
||||||
|
case CommentTask oldCommentTask when newTask instanceof CommentTask newCommentTask -> {
|
||||||
|
newCommentTask.setCommentText(oldCommentTask.getCommentText());
|
||||||
|
newCommentTask.setRequired(oldCommentTask.isRequired());
|
||||||
|
}
|
||||||
|
default -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace in state and preserve order
|
||||||
|
int index = tasksState.indexOf(oldTask);
|
||||||
|
if (index >= 0) {
|
||||||
|
newTask.setTaskOrder(index);
|
||||||
|
tasksState.set(index, newTask);
|
||||||
|
currentTask[0] = newTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTaskConfiguration(configContainer, newTask);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the correct task type based on the loaded task
|
||||||
|
TaskType taskType = getTaskTypeFromTask(task);
|
||||||
|
if (taskType != null) {
|
||||||
|
taskTypeCombo.setValue(taskType);
|
||||||
|
updateTaskConfiguration(configContainer, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
tasksList.add(taskContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the TaskType enum value from a BaseTask instance
|
||||||
|
*/
|
||||||
|
private TaskType getTaskTypeFromTask(BaseTask task) {
|
||||||
|
if (task instanceof ConfirmationTask) return TaskType.CONFIRMATION;
|
||||||
|
if (task instanceof SignatureTask) return TaskType.SIGNATURE;
|
||||||
|
if (task instanceof TodoListTask) return TaskType.TODOLIST;
|
||||||
|
if (task instanceof PhotoTask) return TaskType.PHOTO;
|
||||||
|
if (task instanceof BarcodeTask) return TaskType.BARCODE;
|
||||||
|
if (task instanceof CommentTask) return TaskType.COMMENT;
|
||||||
|
return TaskType.CONFIRMATION; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package de.assecutor.votianlt.repository;
|
||||||
|
|
||||||
|
import de.assecutor.votianlt.model.TaskTemplate;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface TaskTemplateRepository extends MongoRepository<TaskTemplate, ObjectId> {
|
||||||
|
|
||||||
|
List<TaskTemplate> findByUserIdOrderByTemplateNameAsc(ObjectId userId);
|
||||||
|
|
||||||
|
Optional<TaskTemplate> findByUserIdAndTemplateName(ObjectId userId, String templateName);
|
||||||
|
|
||||||
|
void deleteByUserIdAndTemplateName(ObjectId userId, String templateName);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user