Vorbereitung Release 03.0 #94

Merged
tpeetz merged 115 commits from develop/0.3.0 into main 2026-08-25 06:01:18 +00:00
5 changed files with 269 additions and 1 deletions
Showing only changes of commit 9476d8853e - Show all commits
@@ -6,6 +6,7 @@ import com.vaadin.flow.component.sidenav.SideNavItem;
import de.thpeetz.kontor.views.media.MediaActorView;
import de.thpeetz.kontor.views.media.MediaArticleView;
import de.thpeetz.kontor.views.media.MediaFileView;
import de.thpeetz.kontor.views.media.MediaLofiView;
import de.thpeetz.kontor.views.media.MediaVideoView;
import java.util.ArrayList;
@@ -15,6 +16,7 @@ public class MediaConstants {
public static final String MEDIA = "Media";
public static final String MEDIAFILE_ROUTE = "media/mediafile";
public static final String MEDIAVIDEO_ROUTE = "media/mediavideo";
public static final String MEDIALOFI_ROUTE = "media/medialofi";
public static final String MEDIAARTICLE_ROUTE = "media/mediaarticle";
public static final String MEDIA_ROLE = "ROLE_MEDIA";
public static final String MEDIAACTOR_ROUTE = "media/mediaactor";
@@ -22,6 +24,7 @@ public class MediaConstants {
public static final String MEDIAACTORFILE = "Media Actor Files";
private static final String MEDIAFILE = "Media Files";
private static final String MEDIAVIDEO = "Media Videos";
private static final String MEDIALOFI = "Media Lofi";
private static final String MEDIAARTICLE = "Media Article";
private static final String MEDIAACTOR = "Media Actor";
@@ -34,6 +37,7 @@ public class MediaConstants {
public static SideNavItem getMediaNavigation(ArrayList<String> roles) {
SideNavItem media = new SideNavItem(MEDIA, MEDIAFILE_ROUTE, VaadinIcon.VIMEO.create());
media.addItem(new SideNavItem(MEDIAVIDEO, MediaVideoView.class));
media.addItem(new SideNavItem(MEDIALOFI, MediaLofiView.class));
media.addItem(new SideNavItem(MEDIAARTICLE, MediaArticleView.class));
if (roles.contains(MEDIA_ROLE)) {
media.addItem(new SideNavItem(MEDIAFILE, MediaFileView.class));
@@ -1,6 +1,5 @@
package de.thpeetz.kontor.data.common;
import jakarta.persistence.*;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -9,6 +8,13 @@ import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Version;
import java.util.Date;
@Slf4j
@@ -27,6 +27,7 @@ public class MediaFile extends AbstractEntity {
private boolean shouldDownload;
@Nullable
@Column(length = 300)
private String title;
@Nullable
@@ -0,0 +1,113 @@
package de.thpeetz.kontor.views.media;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
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.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;
import de.thpeetz.kontor.data.media.MediaLofi;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MediaLofiForm extends FormLayout {
TextField url = new TextField("URL");
TextField title = new TextField("Title");
TextField fileName = new TextField("Dateiname");
Checkbox review = new Checkbox("Review");
Checkbox shouldDownload = new Checkbox("Download");
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
Binder<MediaLofi> binder = new BeanValidationBinder<>(MediaLofi.class);
public MediaLofiForm() {
addClassName("medialofi-form");
binder.bindInstanceFields(this);
add(url, 2);
add(title, 2);
add(fileName, 2);
add(review, shouldDownload, createButtonsLayout());
}
private HorizontalLayout createButtonsLayout() {
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
save.addClickShortcut(Key.ENTER);
close.addClickShortcut(Key.ESCAPE);
save.addClickListener(event -> validateAndSave());
delete.addClickListener(event -> fireEvent(new DeleteEvent(this, binder.getBean())));
close.addClickListener(event -> fireEvent(new CloseEvent(this)));
binder.addStatusChangeListener(event -> {
save.setEnabled(event.getBinder().isValid());
});
return new HorizontalLayout(save, delete, close);
}
private void validateAndSave() {
if (binder.isValid()) {
fireEvent(new SaveEvent(this, binder.getBean()));
}
}
public void setMediaLofi(MediaLofi mediaLofi) {
binder.setBean(mediaLofi);
}
public abstract static class MediaLofiFormEvent extends ComponentEvent<MediaLofiForm> {
private MediaLofi mediaLofi;
protected MediaLofiFormEvent(MediaLofiForm source, MediaLofi mediaLofi) {
super(source, false);
this.mediaLofi = mediaLofi;
}
public MediaLofi getMediaLofi() {
return mediaLofi;
}
}
public static class SaveEvent extends MediaLofiFormEvent {
SaveEvent(MediaLofiForm source, MediaLofi mediaLofi) {
super(source, mediaLofi);
}
}
public static class DeleteEvent extends MediaLofiFormEvent {
DeleteEvent(MediaLofiForm source, MediaLofi mediaLofi) {
super(source, mediaLofi);
}
}
public static class CloseEvent extends MediaLofiFormEvent {
CloseEvent(MediaLofiForm source) {
super(source, null);
}
}
public void addDeleteListener(ComponentEventListener<DeleteEvent> listener) {
addListener(DeleteEvent.class, listener);
}
public void addSaveListener(ComponentEventListener<SaveEvent> listener) {
addListener(SaveEvent.class, listener);
}
public void addCloseListener(ComponentEventListener<CloseEvent> listener) {
addListener(CloseEvent.class, listener);
}
}
@@ -0,0 +1,144 @@
package de.thpeetz.kontor.views.media;
import org.springframework.context.annotation.Scope;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.Grid;
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 com.vaadin.flow.spring.annotation.SpringComponent;
import de.thpeetz.kontor.constants.MediaConstants;
import de.thpeetz.kontor.data.media.MediaLofi;
import de.thpeetz.kontor.services.MediaLofiService;
import de.thpeetz.kontor.views.common.ColumnToggleContextMenu;
import de.thpeetz.kontor.views.common.MainLayout;
import de.thpeetz.kontor.views.common.SearchFilterField;
import de.thpeetz.kontor.views.common.StatusIcon;
import jakarta.annotation.security.PermitAll;
import lombok.Getter;
@SpringComponent
@Scope("prototype")
@PermitAll
@Route(value = MediaConstants.MEDIALOFI_ROUTE, layout = MainLayout.class)
@PageTitle("MediaLoFi | Media | Kontor")
public class MediaLofiView extends VerticalLayout {
@Getter
Grid<MediaLofi> grid = new Grid<>(MediaLofi.class, false);
Grid.Column<MediaLofi> idColumn = grid.addColumn(MediaLofi::getId).setHeader("ID").setResizable(true);
Grid.Column<MediaLofi> urlColumn = grid.addColumn(MediaLofi::getUrl).setHeader("URL").setResizable(true).setSortable(true);
Grid.Column<MediaLofi> titleColumn = grid.addColumn(MediaLofi::getTitle).setHeader("Titel").setResizable(true).setSortable(true);
Grid.Column<MediaLofi> fileNameColumn = grid.addColumn(MediaLofi::getFileName).setHeader("Dateiname").setResizable(true).setSortable(true);
Grid.Column<MediaLofi> reviewColumn = grid.addComponentColumn(mediaLofi -> StatusIcon.create(mediaLofi.isReview()))
.setHeader("Überprüfung")
.setWidth("6rem");
Grid.Column<MediaLofi> shouldDownloadColumn = grid.addComponentColumn(mediaLofi -> StatusIcon.create(mediaLofi.isShouldDownload()))
.setHeader("Download?")
.setWidth("6rem");
SearchFilterField searchFilterField = new SearchFilterField();
@Getter
MediaLofiForm form;
MediaLofiService service;
public MediaLofiView(MediaLofiService service) {
this.service = service;
addClassName("medialofi-view");
setSizeFull();
configureGrid();
configureForm();
add(getToolbar(), getContent());
updateList();
}
private void configureGrid() {
grid.addClassName("mediavideo-grid");
grid.setSizeFull();
grid.getColumns().forEach(col -> col.setAutoWidth(true));
idColumn.setVisible(false);
grid.asSingleSelect().addValueChangeListener(event -> editMediaLofi(event.getValue()));
}
private void configureForm() {
form = new MediaLofiForm();
form.setWidth("75em");
form.setVisible(false);
form.addSaveListener(this::saveMediaVideo);
form.addDeleteListener(this::deleteMediaLofi);
form.addCloseListener(e -> closeEditor());
}
private void saveMediaVideo(MediaLofiForm.SaveEvent event) {
service.saveMediaLofi(event.getMediaLofi());
updateList();
closeEditor();
}
private void deleteMediaLofi(MediaLofiForm.DeleteEvent event) {
service.deleteMediaLofi(event.getMediaLofi());
updateList();
closeEditor();
}
private Component getContent() {
HorizontalLayout content = new HorizontalLayout(grid, form);
content.setFlexGrow(2, grid);
content.setFlexGrow(1, form);
content.addClassName("content");
content.setSizeFull();
return content;
}
private HorizontalLayout getToolbar() {
searchFilterField.addFilter("Überprüfung");
searchFilterField.addFilter("Download");
searchFilterField.addValueChangeListener(e -> updateList());
Button addMediaLofiButton = new Button("Add MediaLofi");
addMediaLofiButton.addClickListener(click -> addMediaLofi());
Button menuButton = new Button("Show/Hide Columns");
menuButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
ColumnToggleContextMenu<MediaLofi> columnToggleContextMenu = new ColumnToggleContextMenu<>(menuButton);
columnToggleContextMenu.addColumnToggleItem(idColumn);
columnToggleContextMenu.addColumnToggleItem(urlColumn);
columnToggleContextMenu.addColumnToggleItem(titleColumn);
columnToggleContextMenu.addColumnToggleItem(fileNameColumn);
columnToggleContextMenu.addColumnToggleItem(reviewColumn);
columnToggleContextMenu.addColumnToggleItem(shouldDownloadColumn);
HorizontalLayout toolbar = new HorizontalLayout(searchFilterField, addMediaLofiButton, menuButton);
toolbar.addClassName("toolbar");
return toolbar;
}
public void editMediaLofi(MediaLofi mediaLofi) {
if (mediaLofi == null) {
closeEditor();
} else {
form.setMediaLofi(mediaLofi);
form.setVisible(true);
addClassName("editing");
}
}
private void closeEditor() {
form.setMediaLofi(null);
form.setVisible(false);
removeClassName("editing");
}
private void addMediaLofi() {
grid.asSingleSelect().clear();
editMediaLofi(new MediaLofi());
}
public void updateList() {
grid.setItems(service.findAllMediaLofis(searchFilterField.getValue()));
}
}