From 13f3132947d59fd30b03aa1131425d34b858e816 Mon Sep 17 00:00:00 2001 From: kashiuno Date: Thu, 6 Feb 2025 21:22:13 +0300 Subject: [PATCH] Added slots, clients, partners --- src/main/java/aReminder | 1 - .../client/component/ClientEditor.java | 70 ++++++++++++++++ .../client/entity/ClientEntity.java | 19 +++++ .../client/entity/ClientRepository.java | 8 ++ .../client/view/ClientView.java | 76 ++++++++++++++++++ .../qr_access_admin/common/MainLayout.java | 16 ++-- .../partner/component/PartnerEditor.java | 70 ++++++++++++++++ .../partner/entity/PartnerEntity.java | 19 +++++ .../partner/entity/PartnerRepository.java | 8 ++ .../partner/view/PartnerView.java | 76 ++++++++++++++++++ .../slot/component/SlotEditor.java | 79 +++++++++++++++++++ .../slot/entity/SlotEntity.java | 24 ++++++ .../slot/entity/SlotRepository.java | 8 ++ .../qr_access_admin/slot/view/SlotView.java | 76 ++++++++++++++++++ 14 files changed, 544 insertions(+), 6 deletions(-) delete mode 100644 src/main/java/aReminder create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/client/component/ClientEditor.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientEntity.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientRepository.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/client/view/ClientView.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/partner/component/PartnerEditor.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerEntity.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerRepository.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/partner/view/PartnerView.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/slot/component/SlotEditor.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotEntity.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotRepository.java create mode 100644 src/main/java/ru/vyatsu/qr_access_admin/slot/view/SlotView.java diff --git a/src/main/java/aReminder b/src/main/java/aReminder deleted file mode 100644 index 692c9e4..0000000 --- a/src/main/java/aReminder +++ /dev/null @@ -1 +0,0 @@ -TODO: Change package \ No newline at end of file diff --git a/src/main/java/ru/vyatsu/qr_access_admin/client/component/ClientEditor.java b/src/main/java/ru/vyatsu/qr_access_admin/client/component/ClientEditor.java new file mode 100644 index 0000000..af566a4 --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/client/component/ClientEditor.java @@ -0,0 +1,70 @@ +package ru.vyatsu.qr_access_admin.client.component; + +import com.vaadin.flow.component.Composite; +import com.vaadin.flow.component.Key; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.EmailField; +import com.vaadin.flow.data.binder.BeanValidationBinder; +import com.vaadin.flow.data.binder.Binder; +import lombok.Getter; +import lombok.Setter; +import ru.vyatsu.qr_access_admin.client.entity.ClientEntity; + +public class ClientEditor extends Composite { + + public interface SaveListener { + void onSave(ClientEntity qr); + } + + public interface DeleteListener { + void onDelete(ClientEntity qr); + } + + public interface CancelListener { + void onCancel(); + } + + private volatile ClientEntity currentClient; + + @Getter + @Setter + private SaveListener saveListener; + @Getter + @Setter + private DeleteListener deleteListener; + @Getter + @Setter + private CancelListener cancelListener; + + private final Binder binder = new BeanValidationBinder<>(ClientEntity.class); + + public void setCurrentClient(ClientEntity client) { + this.currentClient = client; + binder.setBean(client); + } + + public ClientEditor() { + var email = new EmailField("E-mail"); + + var save = new Button("Сохранить", VaadinIcon.CHECK.create()); + var cancel = new Button("Отмена"); + var delete = new Button("Удалить", VaadinIcon.TRASH.create()); + + binder.forField(email).bind("email"); + + save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + save.addClickListener(e -> saveListener.onSave(currentClient)); + save.addClickShortcut(Key.ENTER); + + delete.addThemeVariants(ButtonVariant.LUMO_ERROR); + delete.addClickListener(e -> deleteListener.onDelete(currentClient)); + + cancel.addClickListener(e -> cancelListener.onCancel()); + + getContent().add(email, new HorizontalLayout(save, cancel, delete)); + } +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientEntity.java b/src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientEntity.java new file mode 100644 index 0000000..833efc8 --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientEntity.java @@ -0,0 +1,19 @@ +package ru.vyatsu.qr_access_admin.client.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "clients") +@Getter +@Setter +public class ClientEntity { + @Id + @Column + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + + @Column + private String email; +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientRepository.java b/src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientRepository.java new file mode 100644 index 0000000..42087ef --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/client/entity/ClientRepository.java @@ -0,0 +1,8 @@ +package ru.vyatsu.qr_access_admin.client.entity; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ClientRepository extends JpaRepository { +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/client/view/ClientView.java b/src/main/java/ru/vyatsu/qr_access_admin/client/view/ClientView.java new file mode 100644 index 0000000..8273cd4 --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/client/view/ClientView.java @@ -0,0 +1,76 @@ +package ru.vyatsu.qr_access_admin.client.view; + +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import ru.vyatsu.qr_access_admin.client.component.ClientEditor; +import ru.vyatsu.qr_access_admin.client.entity.ClientEntity; +import ru.vyatsu.qr_access_admin.client.entity.ClientRepository; +import ru.vyatsu.qr_access_admin.common.MainLayout; + +import java.util.List; + +@Route(value = "clients", layout = MainLayout.class) +@PageTitle("Клиенты") +public class ClientView extends VerticalLayout { + private final ClientRepository repository; + private final Grid grid; + private final ClientEditor editor; + + public ClientView(ClientRepository repository) { + this.repository = repository; + + var addButton = new Button("Добавить клиента", VaadinIcon.PLUS.create()); + grid = new Grid<>(ClientEntity.class); + grid.setColumns("id", "email"); + editor = new ClientEditor(); + + var actionsLayout = new HorizontalLayout(addButton); + add(actionsLayout, grid, editor); + + this.configureEditor(); + + addButton.addClickListener(e -> editClient(new ClientEntity())); + + grid.setHeight("200px"); + grid.asSingleSelect().addValueChangeListener(e -> editClient(e.getValue())); + + refreshClientGrid(); + } + + private void refreshClientGrid() { + List entities = repository.findAll(); + grid.setItems(entities); + } + + private void editClient(ClientEntity client) { + if (client == null) { + editor.setVisible(false); + } else { + editor.setVisible(true); + editor.setCurrentClient(client); + } + } + + private void configureEditor() { + editor.setVisible(false); + + editor.setSaveListener(client -> { + repository.save(client); + refreshClientGrid(); + editClient(null); + }); + + editor.setDeleteListener(client -> { + repository.deleteById(client.getId()); + refreshClientGrid(); + editClient(null); + }); + + editor.setCancelListener(() -> editClient(null)); + } +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/common/MainLayout.java b/src/main/java/ru/vyatsu/qr_access_admin/common/MainLayout.java index 29a95d6..ee2e7f8 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/common/MainLayout.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/common/MainLayout.java @@ -1,9 +1,5 @@ package ru.vyatsu.qr_access_admin.common; -import ru.vyatsu.qr_access_admin.common.view.MainView; -import ru.vyatsu.qr_access_admin.door.view.DoorView; -import ru.vyatsu.qr_access_admin.qr.view.QrView; -import ru.vyatsu.qr_access_admin.unit.view.UnitView; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.applayout.AppLayout; @@ -19,6 +15,13 @@ import com.vaadin.flow.component.tabs.Tabs; import com.vaadin.flow.component.tabs.TabsVariant; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.RouterLink; +import ru.vyatsu.qr_access_admin.client.view.ClientView; +import ru.vyatsu.qr_access_admin.common.view.MainView; +import ru.vyatsu.qr_access_admin.door.view.DoorView; +import ru.vyatsu.qr_access_admin.partner.view.PartnerView; +import ru.vyatsu.qr_access_admin.qr.view.QrView; +import ru.vyatsu.qr_access_admin.slot.view.SlotView; +import ru.vyatsu.qr_access_admin.unit.view.UnitView; import java.util.Optional; @@ -118,7 +121,10 @@ public class MainLayout extends AppLayout { createTab("Домашняя страница", MainView.class), createTab("Устройства", UnitView.class), createTab("Двери", DoorView.class), - createTab("QR-коды", QrView.class) + createTab("QR-коды", QrView.class), + createTab("Слоты", SlotView.class), + createTab("Партнеры", PartnerView.class), + createTab("Клиенты", ClientView.class) }; } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/partner/component/PartnerEditor.java b/src/main/java/ru/vyatsu/qr_access_admin/partner/component/PartnerEditor.java new file mode 100644 index 0000000..5150d81 --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/partner/component/PartnerEditor.java @@ -0,0 +1,70 @@ +package ru.vyatsu.qr_access_admin.partner.component; + +import com.vaadin.flow.component.Composite; +import com.vaadin.flow.component.Key; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.data.binder.BeanValidationBinder; +import com.vaadin.flow.data.binder.Binder; +import lombok.Getter; +import lombok.Setter; +import ru.vyatsu.qr_access_admin.partner.entity.PartnerEntity; + +public class PartnerEditor extends Composite { + + public interface SaveListener { + void onSave(PartnerEntity qr); + } + + public interface DeleteListener { + void onDelete(PartnerEntity qr); + } + + public interface CancelListener { + void onCancel(); + } + + private volatile PartnerEntity currentPartner; + + @Getter + @Setter + private SaveListener saveListener; + @Getter + @Setter + private DeleteListener deleteListener; + @Getter + @Setter + private CancelListener cancelListener; + + private final Binder binder = new BeanValidationBinder<>(PartnerEntity.class); + + public void setCurrentPartner(PartnerEntity partner) { + this.currentPartner = partner; + binder.setBean(partner); + } + + public PartnerEditor() { + var name = new TextField("Наименование"); + + var save = new Button("Сохранить", VaadinIcon.CHECK.create()); + var cancel = new Button("Отмена"); + var delete = new Button("Удалить", VaadinIcon.TRASH.create()); + + binder.forField(name).bind("name"); + + save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + save.addClickListener(e -> saveListener.onSave(currentPartner)); + save.addClickShortcut(Key.ENTER); + + delete.addThemeVariants(ButtonVariant.LUMO_ERROR); + delete.addClickListener(e -> deleteListener.onDelete(currentPartner)); + + cancel.addClickListener(e -> cancelListener.onCancel()); + + getContent().add(name, new HorizontalLayout(save, cancel, delete)); + } +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerEntity.java b/src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerEntity.java new file mode 100644 index 0000000..460af88 --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerEntity.java @@ -0,0 +1,19 @@ +package ru.vyatsu.qr_access_admin.partner.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "partners") +@Getter +@Setter +public class PartnerEntity { + @Id + @Column + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + + @Column + private String name; +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerRepository.java b/src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerRepository.java new file mode 100644 index 0000000..1c4877e --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/partner/entity/PartnerRepository.java @@ -0,0 +1,8 @@ +package ru.vyatsu.qr_access_admin.partner.entity; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PartnerRepository extends JpaRepository { +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/partner/view/PartnerView.java b/src/main/java/ru/vyatsu/qr_access_admin/partner/view/PartnerView.java new file mode 100644 index 0000000..482457e --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/partner/view/PartnerView.java @@ -0,0 +1,76 @@ +package ru.vyatsu.qr_access_admin.partner.view; + +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import ru.vyatsu.qr_access_admin.common.MainLayout; +import ru.vyatsu.qr_access_admin.partner.component.PartnerEditor; +import ru.vyatsu.qr_access_admin.partner.entity.PartnerEntity; +import ru.vyatsu.qr_access_admin.partner.entity.PartnerRepository; + +import java.util.List; + +@Route(value = "partners", layout = MainLayout.class) +@PageTitle("Партнеры") +public class PartnerView extends VerticalLayout { + private final PartnerRepository repository; + private final Grid grid; + private final PartnerEditor editor; + + public PartnerView(PartnerRepository repository) { + this.repository = repository; + + var addButton = new Button("Добавить партнера", VaadinIcon.PLUS.create()); + grid = new Grid<>(PartnerEntity.class); + grid.setColumns("id", "name"); + editor = new PartnerEditor(); + + var actionsLayout = new HorizontalLayout(addButton); + add(actionsLayout, grid, editor); + + this.configureEditor(); + + addButton.addClickListener(e -> editPartner(new PartnerEntity())); + + grid.setHeight("200px"); + grid.asSingleSelect().addValueChangeListener(e -> editPartner(e.getValue())); + + refreshPartnerGrid(); + } + + private void refreshPartnerGrid() { + List entities = repository.findAll(); + grid.setItems(entities); + } + + private void editPartner(PartnerEntity partner) { + if (partner == null) { + editor.setVisible(false); + } else { + editor.setVisible(true); + editor.setCurrentPartner(partner); + } + } + + private void configureEditor() { + editor.setVisible(false); + + editor.setSaveListener(partner -> { + repository.save(partner); + refreshPartnerGrid(); + editPartner(null); + }); + + editor.setDeleteListener(partner -> { + repository.deleteById(partner.getId()); + refreshPartnerGrid(); + editPartner(null); + }); + + editor.setCancelListener(() -> editPartner(null)); + } +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/slot/component/SlotEditor.java b/src/main/java/ru/vyatsu/qr_access_admin/slot/component/SlotEditor.java new file mode 100644 index 0000000..f0adbd0 --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/slot/component/SlotEditor.java @@ -0,0 +1,79 @@ +package ru.vyatsu.qr_access_admin.slot.component; + +import com.vaadin.flow.component.Composite; +import com.vaadin.flow.component.Key; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; +import com.vaadin.flow.component.combobox.ComboBox; +import com.vaadin.flow.component.datetimepicker.DateTimePicker; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.timepicker.TimePicker; +import com.vaadin.flow.data.binder.BeanValidationBinder; +import com.vaadin.flow.data.binder.Binder; +import lombok.Getter; +import lombok.Setter; +import ru.vyatsu.qr_access_admin.door.entity.DoorEntity; +import ru.vyatsu.qr_access_admin.door.entity.DoorRepository; +import ru.vyatsu.qr_access_admin.slot.entity.SlotEntity; + +import java.util.Map; +import java.util.stream.Collectors; + +public class SlotEditor extends Composite { + + public interface SaveListener { + void onSave(SlotEntity qr); + } + + public interface DeleteListener { + void onDelete(SlotEntity qr); + } + + public interface CancelListener { + void onCancel(); + } + + private volatile SlotEntity currentSlot; + + @Getter + @Setter + private SaveListener saveListener; + @Getter + @Setter + private DeleteListener deleteListener; + @Getter + @Setter + private CancelListener cancelListener; + + private final Binder binder = new BeanValidationBinder<>(SlotEntity.class); + + public void setCurrentSlot(SlotEntity slot) { + this.currentSlot = slot; + binder.setBean(slot); + } + + public SlotEditor() { + var startTime = new TimePicker("Начало действия"); + var endTime = new TimePicker("Конец действия"); + + var save = new Button("Сохранить", VaadinIcon.CHECK.create()); + var cancel = new Button("Отмена"); + var delete = new Button("Удалить", VaadinIcon.TRASH.create()); + + binder.forField(startTime).bind("startTime"); + binder.forField(endTime).bind("endTime"); + + save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + save.addClickListener(e -> saveListener.onSave(currentSlot)); + save.addClickShortcut(Key.ENTER); + + delete.addThemeVariants(ButtonVariant.LUMO_ERROR); + delete.addClickListener(e -> deleteListener.onDelete(currentSlot)); + + cancel.addClickListener(e -> cancelListener.onCancel()); + + getContent().add(startTime, endTime, new HorizontalLayout(save, cancel, delete)); + } +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotEntity.java b/src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotEntity.java new file mode 100644 index 0000000..e002dac --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotEntity.java @@ -0,0 +1,24 @@ +package ru.vyatsu.qr_access_admin.slot.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalTime; + +@Entity +@Table(name = "slots") +@Getter +@Setter +public class SlotEntity { + @Id + @Column + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + + @Column + private LocalTime startTime; + + @Column + private LocalTime endTime; +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotRepository.java b/src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotRepository.java new file mode 100644 index 0000000..89d835f --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/slot/entity/SlotRepository.java @@ -0,0 +1,8 @@ +package ru.vyatsu.qr_access_admin.slot.entity; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SlotRepository extends JpaRepository { +} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/slot/view/SlotView.java b/src/main/java/ru/vyatsu/qr_access_admin/slot/view/SlotView.java new file mode 100644 index 0000000..aab75ff --- /dev/null +++ b/src/main/java/ru/vyatsu/qr_access_admin/slot/view/SlotView.java @@ -0,0 +1,76 @@ +package ru.vyatsu.qr_access_admin.slot.view; + +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import ru.vyatsu.qr_access_admin.common.MainLayout; +import ru.vyatsu.qr_access_admin.slot.component.SlotEditor; +import ru.vyatsu.qr_access_admin.slot.entity.SlotEntity; +import ru.vyatsu.qr_access_admin.slot.entity.SlotRepository; + +import java.util.List; + +@Route(value = "slots", layout = MainLayout.class) +@PageTitle("Слоты") +public class SlotView extends VerticalLayout { + private final SlotRepository repository; + private final Grid grid; + private final SlotEditor editor; + + public SlotView(SlotRepository repository) { + this.repository = repository; + + var addButton = new Button("Добавить слот", VaadinIcon.PLUS.create()); + grid = new Grid<>(SlotEntity.class); + grid.setColumns("id", "startTime", "endTime"); + editor = new SlotEditor(); + + var actionsLayout = new HorizontalLayout(addButton); + add(actionsLayout, grid, editor); + + this.configureEditor(); + + addButton.addClickListener(e -> editSlot(new SlotEntity())); + + grid.setHeight("200px"); + grid.asSingleSelect().addValueChangeListener(e -> editSlot(e.getValue())); + + refreshSlotGrid(); + } + + private void refreshSlotGrid() { + List entities = repository.findAll(); + grid.setItems(entities); + } + + private void editSlot(SlotEntity slot) { + if (slot == null) { + editor.setVisible(false); + } else { + editor.setVisible(true); + editor.setCurrentSlot(slot); + } + } + + private void configureEditor() { + editor.setVisible(false); + + editor.setSaveListener(slot -> { + repository.save(slot); + refreshSlotGrid(); + editSlot(null); + }); + + editor.setDeleteListener(slot -> { + repository.deleteById(slot.getId()); + refreshSlotGrid(); + editSlot(null); + }); + + editor.setCancelListener(() -> editSlot(null)); + } +}