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 index af566a4..545aa3c 100644 --- 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 @@ -4,6 +4,7 @@ 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.checkbox.Checkbox; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; @@ -49,12 +50,14 @@ public class ClientEditor extends Composite { public ClientEditor() { var email = new EmailField("E-mail"); + var emailIsConfirmed = new Checkbox("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"); + binder.forField(emailIsConfirmed).bind("emailIsConfirmed"); save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); save.addClickListener(e -> saveListener.onSave(currentClient)); @@ -65,6 +68,6 @@ public class ClientEditor extends Composite { cancel.addClickListener(e -> cancelListener.onCancel()); - getContent().add(email, new HorizontalLayout(save, cancel, delete)); + getContent().add(email, emailIsConfirmed, 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 index 833efc8..9f68e7c 100644 --- 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 @@ -16,4 +16,7 @@ public class ClientEntity { @Column private String email; + + @Column + private Boolean emailIsConfirmed; } 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 index 2d10351..03ad5bd 100644 --- 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 @@ -28,7 +28,7 @@ public class ClientView extends VerticalLayout { var addButton = new Button("Добавить клиента", VaadinIcon.PLUS.create()); grid = new Grid<>(ClientEntity.class); - grid.setColumns("id", "email"); + grid.setColumns("id", "email", "emailIsConfirmed"); editor = new ClientEditor(); var actionsLayout = new HorizontalLayout(addButton); 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 471b825..6dba745 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 @@ -19,7 +19,6 @@ 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.unit.view.UnitView; import java.util.Optional; @@ -120,7 +119,6 @@ public class MainLayout extends AppLayout { createTab("Домашняя страница", MainView.class), createTab("Устройства", UnitView.class), createTab("Двери", DoorView.class), - createTab("QR-коды", QrView.class), createTab("Партнеры", PartnerView.class), createTab("Клиенты", ClientView.class) }; diff --git a/src/main/java/ru/vyatsu/qr_access_admin/door/component/DoorEditor.java b/src/main/java/ru/vyatsu/qr_access_admin/door/component/DoorEditor.java index dca9bb5..2323cab 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/door/component/DoorEditor.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/door/component/DoorEditor.java @@ -15,6 +15,7 @@ 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.door.schedule.component.ScheduleEditor; import ru.vyatsu.qr_access_admin.door.schedule.entity.ScheduleEntity; import ru.vyatsu.qr_access_admin.door.schedule.entity.ScheduleRepository; @@ -22,14 +23,13 @@ import ru.vyatsu.qr_access_admin.unit.entity.UnitRepository; import ru.vyatsu.qr_access_admin.unit.mapper.UnitEntityUnitComboBoxModelMapper; import ru.vyatsu.qr_access_admin.unit.model.UnitComboBoxModel; -import java.util.Collection; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; -public class DoorEditor extends Composite { +public class DoorEditor extends Composite { public interface SaveListener { - void onSave(DoorEntity door, Collection schedule); + void onSave(DoorEditInfo editInfo); } public interface DeleteListener { @@ -44,6 +44,14 @@ public class DoorEditor extends Composite { private final ScheduleEditor scheduleEditor; + private final VerticalLayout additionalDoorsEditor = new VerticalLayout(); + + private final Map additionalDoors = new HashMap<>(); + private final Map additionalDoorsWasLinked = new HashMap<>(); + private final Collection createdAdditionalDoors = new ArrayList<>(); + + private final DoorRepository repository; + @Getter @Setter private SaveListener saveListener; @@ -61,13 +69,100 @@ public class DoorEditor extends Composite { binder.setBean(door); scheduleEditor.setCurrentDoorId(door.getId()); scheduleEditor.refreshScheduleView(); + this.refreshAdditionalDoors(); } - public DoorEditor(UnitRepository unitRepository, ScheduleRepository scheduleRepository) { + private void refreshAdditionalDoors() { + additionalDoorsEditor.removeAll(); + additionalDoors.clear(); + createdAdditionalDoors.clear(); + List existAdditionalDoors = repository.findAllByParentDoorIdsIsNotNull(); + existAdditionalDoors + .stream() + .filter(ad -> currentDoor != null && new HashSet<>(Set.of(ad.getParentDoorIds().split(","))).contains(currentDoor.getId())) + .forEach(ad -> { + HorizontalLayout choose = new HorizontalLayout(); + ComboBox comboBox = new ComboBox<>("Выбрать из имеющихся"); + comboBox.setItems(existAdditionalDoors); + comboBox.setItemLabelGenerator(DoorEntity::getDescription); + comboBox.setValue(ad); + comboBox.setAllowCustomValue(true); + comboBox.addValueChangeListener(e -> { + DoorEntity chosenValue = e.getValue(); + DoorEntity oldValue = e.getOldValue(); + if (oldValue != null) { + additionalDoors.remove(oldValue.getId()); + } + if (chosenValue != null) { + additionalDoors.put(chosenValue.getId(), chosenValue); + } + }); + comboBox.addCustomValueSetListener(e -> { + DoorEntity newDoor = new DoorEntity(); + newDoor.setCount(0); + newDoor.setDescription(e.getDetail()); + newDoor.setUnitId(currentDoor.getUnitId()); + createdAdditionalDoors.add(newDoor); + existAdditionalDoors.add(newDoor); + comboBox.setItems(existAdditionalDoors); + comboBox.setValue(newDoor); + }); + var deleteAdditionalDoor = new Button(VaadinIcon.TRASH.create()); + additionalDoors.put(ad.getId(), ad); + additionalDoorsWasLinked.put(ad.getId(), ad); + deleteAdditionalDoor.addClickListener(ev -> { + additionalDoorsEditor.remove(choose); + additionalDoors.remove(ad.getId()); + }); + choose.add(comboBox, deleteAdditionalDoor); + additionalDoorsEditor.add(choose); + }); + var addAdditionalDoor = new Button("Привязать дверь", VaadinIcon.PLUS.create()); + addAdditionalDoor.addClickListener(e -> { + HorizontalLayout choose = new HorizontalLayout(); + ComboBox comboBox = new ComboBox<>("Выбрать из имеющихся"); + comboBox.setItems(existAdditionalDoors); + comboBox.setItemLabelGenerator(DoorEntity::getDescription); + comboBox.setAllowCustomValue(true); + comboBox.addValueChangeListener(ce -> { + DoorEntity chosenValue = ce.getValue(); + DoorEntity oldValue = ce.getOldValue(); + if (oldValue != null) { + additionalDoors.remove(oldValue.getId()); + } + if (chosenValue != null) { + additionalDoors.put(chosenValue.getId(), chosenValue); + } + }); + comboBox.addCustomValueSetListener(ce -> { + DoorEntity newDoor = new DoorEntity(); + newDoor.setCount(0); + newDoor.setDescription(ce.getDetail()); + newDoor.setUnitId(currentDoor.getUnitId()); + createdAdditionalDoors.add(newDoor); + existAdditionalDoors.add(newDoor); + comboBox.setItems(existAdditionalDoors); + comboBox.setValue(newDoor); + }); + var deleteAdditionalDoor = new Button(VaadinIcon.TRASH.create()); + deleteAdditionalDoor.addClickListener(ev -> { + additionalDoorsEditor.remove(choose); + if (comboBox.getValue() != null) { + additionalDoors.remove(comboBox.getValue().getId()); + } + }); + choose.add(comboBox, deleteAdditionalDoor); + additionalDoorsEditor.addComponentAtIndex(additionalDoorsEditor.getComponentCount() - 1, choose); + }); + additionalDoorsEditor.add(addAdditionalDoor); + } + + public DoorEditor(UnitRepository unitRepository, ScheduleRepository scheduleRepository, DoorRepository repository) { + this.repository = repository; ComboBox unitField = new ComboBox<>("Устройство"); unitField.setRequired(true); unitField.setPageSize(100); - Map units = unitRepository.findAll() + Map units = unitRepository.findAllByAdminEditableIsTrue() .stream() .map(new UnitEntityUnitComboBoxModelMapper()::toModel) .collect(Collectors.toMap(UnitComboBoxModel::clientId, unit -> unit)); @@ -76,6 +171,7 @@ public class DoorEditor extends Composite { IntegerField countField = new IntegerField("Количество мест"); TextField descriptionField = new TextField("Описание"); + var save = new Button("Сохранить", VaadinIcon.CHECK.create()); var cancel = new Button("Отмена"); var delete = new Button("Удалить", VaadinIcon.TRASH.create()); @@ -90,7 +186,7 @@ public class DoorEditor extends Composite { scheduleEditor = new ScheduleEditor(scheduleRepository); - save.addClickListener(e -> saveListener.onSave(currentDoor, scheduleEditor.getNewSchedule())); + save.addClickListener(e -> saveListener.onSave(new DoorEditInfo(currentDoor, scheduleEditor.getNewSchedule(), additionalDoors, additionalDoorsWasLinked))); save.addClickShortcut(Key.ENTER); delete.addThemeVariants(ButtonVariant.LUMO_ERROR); @@ -102,8 +198,19 @@ public class DoorEditor extends Composite { } }); + this.refreshAdditionalDoors(); + cancel.addClickListener(e -> cancelListener.onCancel()); - getContent().add(unitField, countField, descriptionField, scheduleEditor, new HorizontalLayout(save, cancel, delete)); + VerticalLayout mainForm = new VerticalLayout(); + mainForm.add(unitField, countField, descriptionField, scheduleEditor, new HorizontalLayout(save, cancel, delete)); + + getContent().add(mainForm, additionalDoorsEditor); + } + + public record DoorEditInfo(DoorEntity mainDoor, Collection schedule, + Map additionalDoorsToSave, + Map additionalDoorsWasLinked) { + } } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorEntity.java b/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorEntity.java index 09cc660..c8e840a 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorEntity.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorEntity.java @@ -22,4 +22,7 @@ public class DoorEntity { @Column private int count; + + @Column + private String parentDoorIds; } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorRepository.java b/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorRepository.java index 17dbed9..3a27c3b 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorRepository.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/door/entity/DoorRepository.java @@ -2,6 +2,12 @@ package ru.vyatsu.qr_access_admin.door.entity; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface DoorRepository extends JpaRepository { + // TODO: запрашиваем все, чтобы не городить много SQL логики, так как id хранятся через запятую. Будем парсить и фильтровать в коде. + List findAllByParentDoorIdsIsNotNull(); + + List findAllByParentDoorIdsIsNull(); } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/door/view/DoorView.java b/src/main/java/ru/vyatsu/qr_access_admin/door/view/DoorView.java index 0acebb9..b832adb 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/door/view/DoorView.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/door/view/DoorView.java @@ -19,7 +19,10 @@ import ru.vyatsu.qr_access_admin.door.schedule.entity.ScheduleEntity; import ru.vyatsu.qr_access_admin.door.schedule.entity.ScheduleRepository; import ru.vyatsu.qr_access_admin.unit.entity.UnitRepository; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; + +import static org.apache.commons.lang3.StringUtils.isBlank; @Route(value = "doors", layout = MainLayout.class) @PageTitle("Двери") @@ -39,7 +42,8 @@ public class DoorView extends VerticalLayout { var addButton = new Button("Добавить дверь", VaadinIcon.PLUS.create()); grid = new Grid<>(DoorEntity.class); - editor = new DoorEditor(unitRepository, scheduleRepository); + grid.setColumns("description", "unitId", "count"); + editor = new DoorEditor(unitRepository, scheduleRepository, repository); var actionsLayout = new HorizontalLayout(addButton); add(actionsLayout, grid, editor); @@ -56,7 +60,7 @@ public class DoorView extends VerticalLayout { } private void refreshDoorsGrid() { - List entities = repository.findAll(); + List entities = repository.findAllByParentDoorIdsIsNull(); grid.setItems(entities); } @@ -73,12 +77,34 @@ public class DoorView extends VerticalLayout { private void configureEditor() { editor.setVisible(false); - editor.setSaveListener((door, schedule) -> { - DoorEntity savedDoor = repository.save(door); - for (ScheduleEntity se : schedule) { + editor.setSaveListener(doorEditInfo -> { + DoorEntity savedDoor = repository.save(doorEditInfo.mainDoor()); + Map doorsToSave = new HashMap<>(); + doorEditInfo.additionalDoorsToSave().values().forEach(ad -> { + if (isBlank(ad.getParentDoorIds())) { + ad.setParentDoorIds(savedDoor.getId()); + } else { + Set parentDoorIds = Arrays.stream(ad.getParentDoorIds().split(",")) + .collect(Collectors.toSet()); + parentDoorIds.add(savedDoor.getId()); + ad.setParentDoorIds(String.join(",", parentDoorIds)); + } + doorsToSave.put(ad.getId(), ad); + }); + doorEditInfo.additionalDoorsWasLinked().forEach((id, door) -> { + if (!doorEditInfo.additionalDoorsToSave().containsKey(id)) { + Set parentIds = Arrays.stream(door.getParentDoorIds().split(",")) + .collect(Collectors.toSet()); + parentIds.remove(savedDoor.getId()); + door.setParentDoorIds(String.join(",", parentIds)); + doorsToSave.put(id, door); + } + }); + repository.saveAll(doorsToSave.values()); + for (ScheduleEntity se : doorEditInfo.schedule()) { se.setDoorId(savedDoor.getId()); } - scheduleRepository.saveAll(schedule); + scheduleRepository.saveAll(doorEditInfo.schedule()); refreshDoorsGrid(); editDoor(null); }); diff --git a/src/main/java/ru/vyatsu/qr_access_admin/qr/component/QrEditor.java b/src/main/java/ru/vyatsu/qr_access_admin/qr/component/QrEditor.java deleted file mode 100644 index 7d9922c..0000000 --- a/src/main/java/ru/vyatsu/qr_access_admin/qr/component/QrEditor.java +++ /dev/null @@ -1,89 +0,0 @@ -package ru.vyatsu.qr_access_admin.qr.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.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.qr.entity.QrEntity; - -import java.util.Map; -import java.util.stream.Collectors; - -public class QrEditor extends Composite { - - public interface SaveListener { - void onSave(QrEntity qr); - } - - public interface DeleteListener { - void onDelete(QrEntity qr); - } - - public interface CancelListener { - void onCancel(); - } - - private volatile QrEntity currentQr; - - @Getter - @Setter - private SaveListener saveListener; - @Getter - @Setter - private DeleteListener deleteListener; - @Getter - @Setter - private CancelListener cancelListener; - - private final Binder binder = new BeanValidationBinder<>(QrEntity.class); - - public void setCurrentQr(QrEntity qr) { - this.currentQr = qr; - binder.setBean(qr); - } - - public QrEditor(DoorRepository doorRepository) { - ComboBox doorIdField = new ComboBox<>("Идентификатор двери"); - doorIdField.setRequired(true); - doorIdField.setItemLabelGenerator(DoorEntity::getId); - Map doors = doorRepository.findAll() - .stream() - .collect(Collectors.toMap(DoorEntity::getId, e -> e)); - - doorIdField.setItems(doors.values()); - var startDateTime = new DateTimePicker("Начало действия"); - var endDateTime = new DateTimePicker("Актуален до"); - - var save = new Button("Сохранить", VaadinIcon.CHECK.create()); - var cancel = new Button("Отмена"); - var delete = new Button("Удалить", VaadinIcon.TRASH.create()); - - binder.forField(doorIdField) - .withConverter(DoorEntity::getId, doors::get, "Invalid value") - .bind("doorId"); - binder.forField(startDateTime).bind("startDateTime"); - binder.forField(endDateTime).bind("endDateTime"); - - save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); - save.addClickListener(e -> saveListener.onSave(currentQr)); - save.addClickShortcut(Key.ENTER); - - delete.addThemeVariants(ButtonVariant.LUMO_ERROR); - delete.addClickListener(e -> deleteListener.onDelete(currentQr)); - - cancel.addClickListener(e -> cancelListener.onCancel()); - - getContent().add(doorIdField, startDateTime, endDateTime, new HorizontalLayout(save, cancel, delete)); - } -} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/qr/entity/QrEntity.java b/src/main/java/ru/vyatsu/qr_access_admin/qr/entity/QrEntity.java deleted file mode 100644 index 713ef92..0000000 --- a/src/main/java/ru/vyatsu/qr_access_admin/qr/entity/QrEntity.java +++ /dev/null @@ -1,28 +0,0 @@ -package ru.vyatsu.qr_access_admin.qr.entity; - -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; - -import java.time.LocalDateTime; - -@Entity -@Table(name = "qrs") -@Getter -@Setter -public class QrEntity { - - @Id - @Column - @GeneratedValue(strategy = GenerationType.UUID) - private String keyCode; - - @Column - private String doorId; - - @Column - private LocalDateTime startDateTime; - - @Column - private LocalDateTime endDateTime; -} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/qr/entity/QrRepository.java b/src/main/java/ru/vyatsu/qr_access_admin/qr/entity/QrRepository.java deleted file mode 100644 index 836d0cb..0000000 --- a/src/main/java/ru/vyatsu/qr_access_admin/qr/entity/QrRepository.java +++ /dev/null @@ -1,6 +0,0 @@ -package ru.vyatsu.qr_access_admin.qr.entity; - -import org.springframework.data.jpa.repository.JpaRepository; - -public interface QrRepository extends JpaRepository { -} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/qr/view/QrView.java b/src/main/java/ru/vyatsu/qr_access_admin/qr/view/QrView.java deleted file mode 100644 index 4c13488..0000000 --- a/src/main/java/ru/vyatsu/qr_access_admin/qr/view/QrView.java +++ /dev/null @@ -1,78 +0,0 @@ -package ru.vyatsu.qr_access_admin.qr.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 jakarta.annotation.security.PermitAll; -import ru.vyatsu.qr_access_admin.common.MainLayout; -import ru.vyatsu.qr_access_admin.door.entity.DoorRepository; -import ru.vyatsu.qr_access_admin.qr.component.QrEditor; -import ru.vyatsu.qr_access_admin.qr.entity.QrEntity; -import ru.vyatsu.qr_access_admin.qr.entity.QrRepository; - -import java.util.List; - -@Route(value = "qrs", layout = MainLayout.class) -@PageTitle("Коды") -@PermitAll -public class QrView extends VerticalLayout { - private final QrRepository repository; - private final Grid grid; - private final QrEditor editor; - - public QrView(QrRepository repository, DoorRepository doorRepository) { - this.repository = repository; - - var addButton = new Button("Добавить код", VaadinIcon.PLUS.create()); - grid = new Grid<>(QrEntity.class); - editor = new QrEditor(doorRepository); - - var actionsLayout = new HorizontalLayout(addButton); - add(actionsLayout, grid, editor); - - this.configureEditor(); - - addButton.addClickListener(e -> editQr(new QrEntity())); - - grid.setHeight("200px"); - grid.asSingleSelect().addValueChangeListener(e -> editQr(e.getValue())); - - refreshQrGrid(); - } - - private void refreshQrGrid() { - List entities = repository.findAll(); - grid.setItems(entities); - } - - private void editQr(QrEntity qr) { - if (qr == null) { - editor.setVisible(false); - } else { - editor.setVisible(true); - editor.setCurrentQr(qr); - } - } - - private void configureEditor() { - editor.setVisible(false); - - editor.setSaveListener(qr -> { - repository.save(qr); - refreshQrGrid(); - editQr(null); - }); - - editor.setDeleteListener(qr -> { - repository.deleteById(qr.getKeyCode()); - refreshQrGrid(); - editQr(null); - }); - - editor.setCancelListener(() -> editQr(null)); - } -} diff --git a/src/main/java/ru/vyatsu/qr_access_admin/unit/component/UnitEditor.java b/src/main/java/ru/vyatsu/qr_access_admin/unit/component/UnitEditor.java index f85b774..bb60cb7 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/unit/component/UnitEditor.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/unit/component/UnitEditor.java @@ -1,10 +1,10 @@ package ru.vyatsu.qr_access_admin.unit.component; -import ru.vyatsu.qr_access_admin.unit.model.UnitModel; 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; @@ -14,6 +14,12 @@ 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; +import ru.vyatsu.qr_access_admin.partner.entity.PartnerRepository; +import ru.vyatsu.qr_access_admin.unit.model.UnitModel; + +import java.util.Map; +import java.util.stream.Collectors; public class UnitEditor extends Composite { public interface SaveListener { @@ -47,7 +53,7 @@ public class UnitEditor extends Composite { binder.setBean(unit); } - public UnitEditor() { + public UnitEditor(PartnerRepository partnerRepository) { var clientId = new TextField("Идентификатор устройства"); clientId.setRequired(true); var clientSecret = new TextField("Секрет устройства"); @@ -56,6 +62,13 @@ public class UnitEditor extends Composite { clientSecretExpiresAt.setRequiredIndicatorVisible(true); var clientName = new TextField("Человекочитаемое название устройства"); clientName.setRequired(true); + ComboBox partnerField = new ComboBox<>("Партнер"); + partnerField.setPageSize(100); + Map partners = partnerRepository.findAll() + .stream() + .collect(Collectors.toMap(PartnerEntity::getId, p -> p)); + partnerField.setItemLabelGenerator(PartnerEntity::getName); + partnerField.setItems(partners.values()); var save = new Button("Сохранить", VaadinIcon.CHECK.create()); var cancel = new Button("Отмена"); @@ -65,6 +78,9 @@ public class UnitEditor extends Composite { binder.forField(clientSecret).bind("clientSecret"); binder.forField(clientSecretExpiresAt).bind("clientSecretExpiresAt"); binder.forField(clientName).bind("clientName"); + binder.forField(partnerField) + .withConverter(PartnerEntity::getId, partners::get, "Invalid value") + .bind("partnerId"); save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); save.addClickListener(e -> saveListener.onSave(currentUnit)); @@ -75,6 +91,6 @@ public class UnitEditor extends Composite { cancel.addClickListener(e -> cancelListener.onCancel()); - getContent().add(clientId, clientSecret, clientSecretExpiresAt, clientName, new HorizontalLayout(save, cancel, delete)); + getContent().add(clientId, clientSecret, clientSecretExpiresAt, clientName, partnerField, new HorizontalLayout(save, cancel, delete)); } } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/unit/entity/UnitEntity.java b/src/main/java/ru/vyatsu/qr_access_admin/unit/entity/UnitEntity.java index 125b83d..3cb54f1 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/unit/entity/UnitEntity.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/unit/entity/UnitEntity.java @@ -49,4 +49,6 @@ public class UnitEntity { private String tokenSettings; @Column private Boolean adminEditable; + @Column + private String partnerId; } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/unit/mapper/UnitEntityUnitModelMapper.java b/src/main/java/ru/vyatsu/qr_access_admin/unit/mapper/UnitEntityUnitModelMapper.java index 2c363f3..9069b5f 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/unit/mapper/UnitEntityUnitModelMapper.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/unit/mapper/UnitEntityUnitModelMapper.java @@ -33,6 +33,7 @@ public class UnitEntityUnitModelMapper { entity.setRedirectUris(""); entity.setPostLogoutRedirectUris(""); entity.setAdminEditable(true); + entity.setPartnerId(model.getPartnerId()); return entity; } @@ -44,6 +45,7 @@ public class UnitEntityUnitModelMapper { unitModel.setClientName(entity.getClientName()); unitModel.setClientSecretExpiresAt(entity.getClientSecretExpiresAt()); unitModel.setAdminEditable(entity.getAdminEditable()); + unitModel.setPartnerId(entity.getPartnerId()); return unitModel; } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/unit/model/UnitModel.java b/src/main/java/ru/vyatsu/qr_access_admin/unit/model/UnitModel.java index bd7ac73..d5b50f9 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/unit/model/UnitModel.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/unit/model/UnitModel.java @@ -28,4 +28,6 @@ public class UnitModel { private String clientName; private boolean adminEditable; + + private String partnerId; } diff --git a/src/main/java/ru/vyatsu/qr_access_admin/unit/view/UnitView.java b/src/main/java/ru/vyatsu/qr_access_admin/unit/view/UnitView.java index edddb46..59f9d7d 100644 --- a/src/main/java/ru/vyatsu/qr_access_admin/unit/view/UnitView.java +++ b/src/main/java/ru/vyatsu/qr_access_admin/unit/view/UnitView.java @@ -9,6 +9,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import jakarta.annotation.security.PermitAll; import ru.vyatsu.qr_access_admin.common.MainLayout; +import ru.vyatsu.qr_access_admin.partner.entity.PartnerRepository; import ru.vyatsu.qr_access_admin.unit.component.UnitEditor; import ru.vyatsu.qr_access_admin.unit.entity.UnitEntity; import ru.vyatsu.qr_access_admin.unit.entity.UnitRepository; @@ -27,14 +28,14 @@ public class UnitView extends VerticalLayout { private final UnitEditor editor; private final UnitEntityUnitModelMapper entityModelMapper; - public UnitView(UnitRepository unitRepository, UnitEntityUnitModelMapper entityModelMapper) { + public UnitView(UnitRepository unitRepository, UnitEntityUnitModelMapper entityModelMapper, PartnerRepository partnerRepository) { this.unitRepository = unitRepository; this.entityModelMapper = entityModelMapper; var addButton = new Button("Добавить устройство", VaadinIcon.PLUS.create()); grid = new Grid<>(UnitModel.class); grid.setColumns("clientId", "clientName", "clientSecretExpiresAt"); - editor = new UnitEditor(); + editor = new UnitEditor(partnerRepository); var actionsLayout = new HorizontalLayout(addButton); add(actionsLayout, grid, editor);