import sources from develop/0.1.0
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package de.thpeetz.kontor;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import com.vaadin.flow.component.page.AppShellConfigurator;
|
||||
import com.vaadin.flow.server.PWA;
|
||||
import com.vaadin.flow.theme.Theme;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
@Slf4j
|
||||
@EnableJpaAuditing
|
||||
@SpringBootApplication
|
||||
@Theme(value = "kontor")
|
||||
@PWA(name = "Vaadin Kontor", shortName = "Kontor", offlinePath = "offline.html", offlineResources = { "images/offline.png" })
|
||||
public class Application implements AppShellConfigurator {
|
||||
|
||||
public static void main(String[] args) {
|
||||
log.info("Starting Kontor application");
|
||||
SpringApplication.run(Application.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package de.thpeetz.kontor.admin;
|
||||
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.sidenav.SideNavItem;
|
||||
import com.vaadin.flow.router.RouterLink;
|
||||
import de.thpeetz.kontor.admin.views.*;
|
||||
import de.thpeetz.kontor.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.views.ComicWorkView;
|
||||
import de.thpeetz.kontor.media.MediaConstants;
|
||||
import de.thpeetz.kontor.media.views.MediaActorFileView;
|
||||
|
||||
public class AdminConstants {
|
||||
|
||||
|
||||
private AdminConstants() {
|
||||
// private constructor to hide the implicit public one
|
||||
}
|
||||
|
||||
public static final String ADMIN_TITLE = "Verwaltung";
|
||||
public static final String AUTHORIZATION = "Berechtigungen";
|
||||
public static final String AUTHORIZATION_ROUTE = "/admin/authorization";
|
||||
public static final String DATA = "Daten";
|
||||
public static final String METADATA_ROUTE = "admin/metadata";
|
||||
public static final String ROLE = "Rollen";
|
||||
public static final String ROLE_ROUTE = "/admin/role";
|
||||
public static final String USER = "Benutzer";
|
||||
public static final String USER_ROUTE = "/admin/user";
|
||||
public static final String ADMIN = "admin";
|
||||
public static final String ADMIN_ROUTE = "/admin";
|
||||
|
||||
public static RouterLink getUserNavigation() {
|
||||
return new RouterLink(USER, UserView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getRoleNavigation() {
|
||||
return new RouterLink(ROLE, RoleView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getAuthorizationNavigation() {
|
||||
return new RouterLink(AUTHORIZATION, AuthorizationView.class);
|
||||
}
|
||||
|
||||
public static SideNavItem getAdminNavigation() {
|
||||
SideNavItem administration = new SideNavItem(ADMIN_TITLE, USER_ROUTE, VaadinIcon.GROUP.create());
|
||||
administration.addItem(new SideNavItem(USER, USER_ROUTE, VaadinIcon.USERS.create()));
|
||||
administration.addItem(new SideNavItem(ROLE, RoleView.class));
|
||||
SideNavItem data = new SideNavItem(DATA, AUTHORIZATION_ROUTE, VaadinIcon.DATABASE.create());
|
||||
data.addItem(new SideNavItem(ComicConstants.COMICWORK, ComicWorkView.class));
|
||||
data.addItem(new SideNavItem(MediaConstants.MEDIAACTORFILE, MediaActorFileView.class));
|
||||
data.addItem(new SideNavItem(AUTHORIZATION, AuthorizationView.class));
|
||||
data.addItem(new SideNavItem("Data Import", ModuleDataView.class));
|
||||
data.addItem(new SideNavItem("Meta Data", MetaDataView.class));
|
||||
administration.addItem(data);
|
||||
return administration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package de.thpeetz.kontor.admin;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "mail")
|
||||
public class MailProperties {
|
||||
|
||||
private String protocol;
|
||||
private String host;
|
||||
private Integer port;
|
||||
private String userName;
|
||||
private String password;
|
||||
private Boolean startTls;
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Boolean getStartTls() {
|
||||
return startTls;
|
||||
}
|
||||
|
||||
public void setStartTls(Boolean startTls) {
|
||||
this.startTls = startTls;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("MailProperties{");
|
||||
sb.append("protocol='").append(protocol).append('\'');
|
||||
sb.append(", host='").append(host).append('\'');
|
||||
sb.append(", port=").append(port);
|
||||
sb.append(", starttls=").append(startTls);
|
||||
sb.append(", userName='").append(userName).append('\'');
|
||||
sb.append(", password='").append(password).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
package de.thpeetz.kontor.admin;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.*;
|
||||
import de.thpeetz.kontor.admin.repository.AuthorizationMatrixRepository;
|
||||
import de.thpeetz.kontor.admin.repository.MailAccountRepository;
|
||||
import de.thpeetz.kontor.admin.repository.UserRepository;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.admin.services.MetaDataService;
|
||||
import de.thpeetz.kontor.mailclient.data.MailAccount;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEvent> {
|
||||
boolean alreadySetup = false;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private AuthorizationMatrixRepository authorizationMatrixRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
private MailAccountRepository mailAccountRepository;
|
||||
|
||||
@Autowired
|
||||
private MailProperties mailProperties;
|
||||
|
||||
@Autowired
|
||||
private AdminService adminService;
|
||||
|
||||
@Autowired
|
||||
private MetaDataService metaDataService;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
if (alreadySetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create initial roles and users
|
||||
Role adminRole = adminService.addRole("ROLE_ADMIN");
|
||||
Role userRole = adminService.addRole("ROLE_USER");
|
||||
List<User> users = userRepository.findAll();
|
||||
if (users.isEmpty()) {
|
||||
User adminUser = initAdminUser();
|
||||
initMatrix(adminRole, adminUser);
|
||||
initMatrix(userRole, adminUser);
|
||||
}
|
||||
log.info("MailProperties: {}", mailProperties);
|
||||
initMail(mailProperties);
|
||||
|
||||
initMetaData();
|
||||
}
|
||||
|
||||
private void initMail(MailProperties mailProperties) {
|
||||
log.info("initMail: Host {} with User {}", mailProperties.getHost(), mailProperties.getUserName());
|
||||
if (mailProperties.getHost() == null || mailProperties.getHost().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
boolean addMailAccount = false;
|
||||
List<MailAccount> mailAccounts = mailAccountRepository.findAll();
|
||||
if (mailAccounts.isEmpty()) {
|
||||
addMailAccount = true;
|
||||
}
|
||||
for (MailAccount mailAccount : mailAccounts) {
|
||||
String accountUser = mailAccount.getUserName();
|
||||
String propertyUser = mailProperties.getUserName();
|
||||
String accountHost = mailAccount.getHost();
|
||||
String propertyHost = mailProperties.getHost();
|
||||
if (propertyHost.equals(accountHost) && propertyUser.equals(accountUser)) {
|
||||
log.debug("already configured: {}", mailAccount);
|
||||
} else {
|
||||
addMailAccount = true;
|
||||
}
|
||||
}
|
||||
if (addMailAccount) {
|
||||
log.info("add Mail Account: {}", mailProperties);
|
||||
MailAccount mailAccount = new MailAccount();
|
||||
mailAccount.setProtocol(mailProperties.getProtocol());
|
||||
mailAccount.setHost(mailProperties.getHost());
|
||||
mailAccount.setPort(mailProperties.getPort());
|
||||
mailAccount.setUserName(mailProperties.getUserName());
|
||||
mailAccount.setPassword(mailProperties.getPassword());
|
||||
mailAccount.setStartTls(mailProperties.getStartTls());
|
||||
mailAccountRepository.save(mailAccount);
|
||||
}
|
||||
}
|
||||
|
||||
private void initMatrix(Role role, User user) {
|
||||
log.info("initMatrix: Role {} for User {}", role.getName(), user.getUserName());
|
||||
Collection<AuthorizationMatrix> configuredRoles = authorizationMatrixRepository.findByUser(user);
|
||||
if (configuredRoles.stream().anyMatch(matrix -> matrix.getRole().getId().equals(role.getId()))) {
|
||||
log.info("Role {} already defined", role.getName());
|
||||
} else {
|
||||
log.info("add Role {} to User {}", role.getName(), user.getUserName());
|
||||
final AuthorizationMatrix adminMatrix = new AuthorizationMatrix();
|
||||
adminMatrix.setUser(user);
|
||||
adminMatrix.setRole(role);
|
||||
authorizationMatrixRepository.save(adminMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
private User initAdminUser() {
|
||||
log.info("initAdminUser");
|
||||
User admin = userRepository.findByUserName("admin");
|
||||
if (admin == null) {
|
||||
log.info("User admin not found, will be created.");
|
||||
admin = new User();
|
||||
admin.setFirstName("Admin");
|
||||
admin.setLastName("Administrator");
|
||||
admin.setUserName("admin");
|
||||
admin.setEmail("admin@example.org");
|
||||
admin.setPassword(passwordEncoder.encode("admin"));
|
||||
userRepository.save(admin);
|
||||
}
|
||||
return admin;
|
||||
}
|
||||
|
||||
private void initMetaData() {
|
||||
log.info("initMetaData");
|
||||
MetaDataTable mediaArticleTable = metaDataService.getTable("media_article");
|
||||
metaDataService.getColumn(mediaArticleTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "ID", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaArticleTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaArticleTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaArticleTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaArticleTable, "url", "link_url", "TEXT", "UNIQUE", 5, Boolean.TRUE, "URL", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaArticleTable, "review", "review", "BOOLEAN", null, 6, Boolean.TRUE, "Review", Boolean.TRUE, "Review");
|
||||
metaDataService.getColumn(mediaArticleTable, "title", "title", "TEXT", null, 7, Boolean.TRUE, "Title", Boolean.FALSE, null);
|
||||
MetaDataTable mediaVideoTable = metaDataService.getTable("media_video");
|
||||
metaDataService.getColumn(mediaVideoTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "ID", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "Version", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "url", "link_url", "TEXT", "UNIQUE", 5, Boolean.TRUE, "URL", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "review", "review", "BOOLEAN", null, 6, Boolean.TRUE, "Review", Boolean.TRUE, "Review");
|
||||
metaDataService.getColumn(mediaVideoTable, "should_download", "should_download", "BOOLEAN", null, 7, Boolean.TRUE, "Download", Boolean.TRUE, "Download");
|
||||
metaDataService.getColumn(mediaVideoTable, "title", "title", "TEXT", null, 8, Boolean.TRUE, "Title", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "file_name", "file_name", "TEXT", null, 9, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "path", "path", "TEXT", null, 10, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaVideoTable, "cloud_link", "cloud_link", "TEXT", null, 11, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable mediaFileTable = metaDataService.getTable("media_file");
|
||||
metaDataService.getColumn(mediaFileTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "ID", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "Created", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "Modified", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "Version", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "url", "link_url", "TEXT", "UNIQUE", 5, Boolean.TRUE, "URL", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "review", "review", "BOOLEAN", null, 6, Boolean.TRUE, "Review", Boolean.TRUE, "Review");
|
||||
metaDataService.getColumn(mediaFileTable, "should_download", "should_download", "BOOLEAN", null, 7, Boolean.TRUE, "Download", Boolean.TRUE, "Download");
|
||||
metaDataService.getColumn(mediaFileTable, "title", "title", "TEXT", null, 8, Boolean.TRUE, "Title", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "file_name", "file_name", "TEXT", null, 9, Boolean.TRUE, "Dateiname", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "path", "path", "TEXT", null, 10, Boolean.TRUE, "Verzeichnis", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaFileTable, "cloud_link", "cloud_link", "TEXT", null, 11, Boolean.TRUE, "Cloud Link", Boolean.FALSE, null);
|
||||
MetaDataTable mediaActorTable = metaDataService.getTable("media_actor");
|
||||
metaDataService.getColumn(mediaActorTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "ID", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "Created", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "Modified", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "Version", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
MetaDataTable mediaActorFileTable = metaDataService.getTable("media_actor_file");
|
||||
metaDataService.getColumn(mediaActorFileTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "ID", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorFileTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "Created", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorFileTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "Modified", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorFileTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "Version", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mediaActorFileTable, "media_actor_id", "media_actor_id", "TEXT", null, 5, Boolean.TRUE, "Actor", Boolean.FALSE, null, "name");
|
||||
metaDataService.getColumn(mediaActorFileTable, "media_file_id", "media_file_id", "TEXT", null, 6, Boolean.TRUE, "File", Boolean.FALSE, null, "title");
|
||||
MetaDataTable artistTable = metaDataService.getTable("artist");
|
||||
metaDataService.getColumn(artistTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(artistTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(artistTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(artistTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(artistTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable publisherTable = metaDataService.getTable("publisher");
|
||||
metaDataService.getColumn(publisherTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(publisherTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(publisherTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(publisherTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(publisherTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
MetaDataTable comicTable = metaDataService.getTable("comic");
|
||||
metaDataService.getColumn(comicTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "ID", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicTable, "completed", "completed", "BOOLEAN", null, 5, Boolean.TRUE, "Complete", Boolean.TRUE, "Complete");
|
||||
metaDataService.getColumn(comicTable, "current_order", "current_order", "BOOLEAN", null, 6, Boolean.TRUE, "Bestellung", Boolean.TRUE, "Bestellung");
|
||||
metaDataService.getColumn(comicTable, "title", "title", "TEXT", "UNIQUE", 7, Boolean.TRUE, "Title", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicTable, "publisher_id", "publisher_id", "TEXT", null, 8, Boolean.TRUE, "Verlag", Boolean.FALSE, null, "name");
|
||||
MetaDataTable issueTable = metaDataService.getTable("issue");
|
||||
metaDataService.getColumn(issueTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "in_stock", "in_stock", "BOOLEAN", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "is_read", "is_read", "BOOLEAN", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "issue_number", "issue_number", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(issueTable, "comic_id", "comic_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null, "title");
|
||||
metaDataService.getColumn(issueTable, "volume_id", "volume_id", "TEXT", null, 9, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable volumeTable = metaDataService.getTable("volume");
|
||||
metaDataService.getColumn(volumeTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(volumeTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(volumeTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(volumeTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(volumeTable, "name", "name", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(volumeTable, "comic_id", "comic_id", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable tpbTable = metaDataService.getTable("trade_paperback");
|
||||
metaDataService.getColumn(tpbTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "issue_start", "issue_start", "LONG", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "issue_end", "issue_end", "LONG", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "name", "name", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tpbTable, "comic_id", "comic_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null, "title");
|
||||
MetaDataTable storyArcTable = metaDataService.getTable("story_arc");
|
||||
metaDataService.getColumn(storyArcTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(storyArcTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(storyArcTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(storyArcTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(storyArcTable, "name", "name", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(storyArcTable, "comic_id", "comic_id", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable worktypeTable = metaDataService.getTable("worktype");
|
||||
metaDataService.getColumn(worktypeTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(worktypeTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(worktypeTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(worktypeTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(worktypeTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable comicworkTable = metaDataService.getTable("comic_work");
|
||||
metaDataService.getColumn(comicworkTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicworkTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicworkTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicworkTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicworkTable, "artist_id", "artist_id", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicworkTable, "comic_id", "comic_id", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(comicworkTable, "work_type_id", "work_type_id", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable authorTable = metaDataService.getTable("author");
|
||||
metaDataService.getColumn(authorTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorTable, "first_name", "first_name", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorTable, "last_name", "last_name", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable articleTable = metaDataService.getTable("article");
|
||||
metaDataService.getColumn(articleTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleTable, "title", "title", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable articleAuthorTable = metaDataService.getTable("article_author");
|
||||
metaDataService.getColumn(articleAuthorTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleAuthorTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleAuthorTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleAuthorTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleAuthorTable, "article_id", "article_id", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(articleAuthorTable, "author_id", "author_id", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable bookTable = metaDataService.getTable("book");
|
||||
metaDataService.getColumn(bookTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "isbn", "isbn", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "title", "title", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "year", "year", "LONG", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookTable, "publisher_id", "publisher_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable bookAuthorTable = metaDataService.getTable("book_author");
|
||||
metaDataService.getColumn(bookAuthorTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookAuthorTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookAuthorTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookAuthorTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookAuthorTable, "author_id", "author_id", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookAuthorTable, "book_id", "book_id", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable bookshelfPublisherTable = metaDataService.getTable("bookshelf_publisher");
|
||||
metaDataService.getColumn(bookshelfPublisherTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookshelfPublisherTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookshelfPublisherTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookshelfPublisherTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(bookshelfPublisherTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable sportTable = metaDataService.getTable("sport");
|
||||
metaDataService.getColumn(sportTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(sportTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(sportTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(sportTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(sportTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable playerTable = metaDataService.getTable("player");
|
||||
metaDataService.getColumn(playerTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(playerTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(playerTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(playerTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(playerTable, "first_name", "first_name", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(playerTable, "last_name", "last_name", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable teamTable = metaDataService.getTable("team");
|
||||
metaDataService.getColumn(teamTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(teamTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(teamTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(teamTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(teamTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(teamTable, "short_name", "short_name", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(teamTable, "sport_id", "sport_id", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable vendorTable = metaDataService.getTable("vendor");
|
||||
metaDataService.getColumn(vendorTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(vendorTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(vendorTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(vendorTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(vendorTable, "name", "name", "TEXT", "UNIQUE", 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable fieldPositionTable = metaDataService.getTable("field_position");
|
||||
metaDataService.getColumn(fieldPositionTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(fieldPositionTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(fieldPositionTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(fieldPositionTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(fieldPositionTable, "name", "name", "TEXT", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(fieldPositionTable, "short_name", "short_name", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(fieldPositionTable, "sport_id", "sport_id", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable roosterTable = metaDataService.getTable("rooster");
|
||||
metaDataService.getColumn(roosterTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "year", "year", "LONG", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "player_id", "player_id", "TEXT", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "position_id", "position_id", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roosterTable, "team_id", "team_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable cardSetTable = metaDataService.getTable("card_set");
|
||||
metaDataService.getColumn(cardSetTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "insert_set", "insert_set", "BOOLEAN", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "parallel_set", "parallel_set", "BOOLEAN", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "name", "name", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardSetTable, "vendor_id", "vendor_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable cardTable = metaDataService.getTable("card");
|
||||
metaDataService.getColumn(cardTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "card_number", "card_number", "LONG", null, 5, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "year", "year", "LONG", null, 6, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "card_set_id", "card_set_id", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "rooster_id", "rooster_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(cardTable, "vendor_id", "vendor_id", "TEXT", null, 9, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
MetaDataTable userTable = metaDataService.getTable("user");
|
||||
metaDataService.getColumn(userTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "first_name", "first_name", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "last_name", "last_name", "TEXT", null, 6, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "user_name", "user_name", "TEXT", "UNIQUE", 7, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "email", "email", "TEXT", null, 8, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "password", "password", "TEXT", null, 9, Boolean.FALSE, "Password", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(userTable, "enabled", "enabled", "BOOLEAN", null, 10, Boolean.TRUE, "", Boolean.TRUE, null);
|
||||
MetaDataTable tokenTable = metaDataService.getTable("token");
|
||||
metaDataService.getColumn(tokenTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "token", "token", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "name", "name", "TEXT", null, 6, Boolean.TRUE, "Name", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "last_used_date", "used", "TIMESTAMP", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(tokenTable, "enabled", "enabled", "BOOLEAN", null, 8, Boolean.TRUE, "", Boolean.TRUE, "Enabled");
|
||||
metaDataService.getColumn(tokenTable, "user_id", "user_id", "TEXT", null, 9, Boolean.TRUE, "User", Boolean.FALSE, null, "user_name");
|
||||
MetaDataTable roleTable = metaDataService.getTable("role");
|
||||
metaDataService.getColumn(roleTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roleTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roleTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roleTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(roleTable, "name", "name", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
MetaDataTable authorizationMatrix = metaDataService.getTable("authorization_matrix");
|
||||
metaDataService.getColumn(authorizationMatrix, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorizationMatrix, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorizationMatrix, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorizationMatrix, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(authorizationMatrix, "user_id", "user_id", "TEXT", null, 5, Boolean.TRUE, "User", Boolean.FALSE, null, "user_name");
|
||||
metaDataService.getColumn(authorizationMatrix, "role_id", "role_id", "TEXT", null, 6, Boolean.TRUE, "Role", Boolean.FALSE, null, "name");
|
||||
MetaDataTable moduleDataTable = metaDataService.getTable("module_data");
|
||||
metaDataService.getColumn(moduleDataTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(moduleDataTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(moduleDataTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(moduleDataTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(moduleDataTable, "module_name", "module_name", "TEXT", "UNIQUE", 5, Boolean.TRUE, "Module", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(moduleDataTable, "import_data", "import_data", "BOOLEAN", null, 6, Boolean.TRUE, "Import Data?", Boolean.TRUE, "Import Data");
|
||||
MetaDataTable mailAccountTable = metaDataService.getTable("mail_account");
|
||||
metaDataService.getColumn(mailAccountTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "host", "host", "TEXT", null, 5, Boolean.TRUE, "Host", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "port", "port", "LONG", null, 6, Boolean.TRUE, "Port", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "protocol", "protocol", "TEXT", null, 7, Boolean.TRUE, "Protocol", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "user_name", "user_name", "TEXT", null, 8, Boolean.TRUE, "Username", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "password", "password", "TEXT", null, 9, Boolean.FALSE, "Password", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailAccountTable, "start_tls", "start_tls", "BOOLEAN", null, 10, Boolean.TRUE, "StartTLS", Boolean.TRUE, "StartTLS");
|
||||
MetaDataTable mailTable = metaDataService.getTable("mail");
|
||||
metaDataService.getColumn(mailTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "folder", "folder", "TEXT", null, 5, Boolean.TRUE, "Folder", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "subject", "subject", "TEXT", null, 6, Boolean.TRUE, "Subject", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "body", "body", "TEXT", null, 7, Boolean.FALSE, "Body", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "sent_date", "created", "TIMESTAMP", null, 8, Boolean.FALSE, "Gesendet", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(mailTable, "received_date", "created", "TIMESTAMP", null, 9, Boolean.FALSE, "Empfangen", Boolean.FALSE, null);
|
||||
MetaDataTable metaDataTableTable = metaDataService.getTable("meta_data_table");
|
||||
metaDataService.getColumn(metaDataTableTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataTableTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataTableTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataTableTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataTableTable, "table_name", "table_name", "TEXT", "UNIQUE", 5, Boolean.TRUE, "Table", Boolean.FALSE, null);
|
||||
MetaDataTable metaDataColumnTable = metaDataService.getTable("meta_data_column");
|
||||
metaDataService.getColumn(metaDataColumnTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "column_name", "column_name", "TEXT", null, 5, Boolean.TRUE, "Column", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "column_sync_name", "column_sync_name", "TEXT", null, 6, Boolean.TRUE, "SQLite Column", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "column_type", "column_type", "TEXT", null, 7, Boolean.TRUE, "Type", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "column_modifier", "column_modifier", "TEXT", null, 8, Boolean.TRUE, "Modifier", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "column_order", "column_order", "LONG", null, 9, Boolean.TRUE, "Order", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "is_shown", "is_shown", "BOOLEAN", null, 10, Boolean.TRUE, "Is Shown", Boolean.TRUE, "Is Shown");
|
||||
metaDataService.getColumn(metaDataColumnTable, "column_label", "column_label", "TEXT", null, 11, Boolean.TRUE, "Label", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "show_filter", "show_filter", "BOOLEAN", null, 12, Boolean.TRUE, "Show Filter", Boolean.TRUE, "Show Filter");
|
||||
metaDataService.getColumn(metaDataColumnTable, "filter_label", "filter_label", "TEXT", null, 13, Boolean.TRUE, "Filter Label", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "ref_column", "ref_column", "TEXT", null, 14, Boolean.TRUE, "Ref Column", Boolean.FALSE, null);
|
||||
metaDataService.getColumn(metaDataColumnTable, "table_id", "table_id", "TEXT", null, 15, Boolean.TRUE, "Table", Boolean.FALSE, null, "table_name");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
public class AuthorizationMatrix extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
@NotNull
|
||||
private User user;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "role_id")
|
||||
@NotNull
|
||||
private Role role;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("AuthorizationMatrix{");
|
||||
sb.append("user=").append(user.getUserName());
|
||||
sb.append(", role=").append(role.getName());
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Table(
|
||||
indexes = @Index(columnList = "columnName, table_id"),
|
||||
uniqueConstraints = @UniqueConstraint(columnNames = {"table_id", "columnOrder"})
|
||||
)
|
||||
public class MetaDataColumn extends AbstractEntity {
|
||||
|
||||
@NotNull
|
||||
private String columnName;
|
||||
|
||||
private String columnSyncName;
|
||||
|
||||
private String columnType;
|
||||
|
||||
@Nullable
|
||||
private String columnModifier;
|
||||
|
||||
private Integer columnOrder;
|
||||
|
||||
private Boolean isShown;
|
||||
|
||||
private String columnLabel;
|
||||
|
||||
private Boolean showFilter = Boolean.FALSE;
|
||||
|
||||
private String filterLabel;
|
||||
|
||||
private String refColumn;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "table_id")
|
||||
@NotNull
|
||||
private MetaDataTable table;
|
||||
|
||||
public String getTableName() {
|
||||
return table.getTableName();
|
||||
}
|
||||
|
||||
public String updateColumnName(String value) {
|
||||
if (!this.getColumnName().equals(value)) {
|
||||
this.setColumnName(value);
|
||||
log.info("update columnName");
|
||||
return "updated " + this.getId() + " with " + value + "\n";
|
||||
}
|
||||
return "no changes for " + this.getId() + "\n";
|
||||
}
|
||||
|
||||
public String updateColumnSyncName(String value) {
|
||||
if (!this.getColumnSyncName().equals(value)) {
|
||||
this.setColumnSyncName(value);
|
||||
log.info("update columnSyncName");
|
||||
return "updated " + this.getId() + " with " + value + "\n";
|
||||
}
|
||||
return "no changes for " + this.getId() + "\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Table(
|
||||
indexes = @Index(columnList = "tableName"),
|
||||
uniqueConstraints = @UniqueConstraint(columnNames = {"tableName"})
|
||||
)
|
||||
public class MetaDataTable extends AbstractEntity {
|
||||
|
||||
@NotNull
|
||||
private String tableName;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "table")
|
||||
private List<MetaDataColumn> tableColumns = new LinkedList<>();
|
||||
|
||||
public String updateTableName(String value) {
|
||||
if (!this.getTableName().equals(value)) {
|
||||
this.setTableName(value);
|
||||
log.info("update tableName");
|
||||
return "updated " + this.getId() + " with " + value;
|
||||
}
|
||||
return "no changes for " + this.getId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@Table(
|
||||
indexes = @Index(columnList = "moduleName"),
|
||||
uniqueConstraints = @UniqueConstraint(columnNames = {"moduleName"})
|
||||
)
|
||||
public class ModuleData extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String moduleName;
|
||||
|
||||
private Boolean importData;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public class Role extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "role")
|
||||
@Nullable
|
||||
private List<AuthorizationMatrix> matrix;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "token"), uniqueConstraints = @UniqueConstraint(columnNames = {"token"}))
|
||||
public class Token extends AbstractEntity {
|
||||
|
||||
private String token;
|
||||
|
||||
private String name;
|
||||
|
||||
private Date lastUsedDate;
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name="user_id")
|
||||
@NotNull
|
||||
private User user;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "userName"), uniqueConstraints = @UniqueConstraint(columnNames = {"userName"}))
|
||||
public class User extends AbstractEntity {
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@NotEmpty
|
||||
private String userName;
|
||||
|
||||
private String email;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
|
||||
@Nullable
|
||||
private List<AuthorizationMatrix> matrix = new LinkedList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
|
||||
@Nullable
|
||||
private List<Token> tokens = new LinkedList<>();
|
||||
|
||||
public String getFullName() {
|
||||
StringBuilder fullNamBuilder = new StringBuilder();
|
||||
if (firstName != null) {
|
||||
fullNamBuilder.append(firstName);
|
||||
}
|
||||
if (lastName != null) {
|
||||
if (fullNamBuilder.length() > 0) {
|
||||
fullNamBuilder.append(" ");
|
||||
}
|
||||
fullNamBuilder.append(lastName);
|
||||
}
|
||||
return fullNamBuilder.toString();
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AuthorizationMatrixRepository extends JpaRepository<AuthorizationMatrix, String> {
|
||||
|
||||
List<AuthorizationMatrix> findByUser(User user);
|
||||
|
||||
List<AuthorizationMatrix> findByRole(Role role);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import de.thpeetz.kontor.mailclient.data.MailAccount;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
|
||||
public interface MailAccountRepository extends JpaRepository<MailAccount, String> {
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.MetaDataColumn;
|
||||
import de.thpeetz.kontor.admin.data.MetaDataTable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MetaDataColumnRepository extends JpaRepository<MetaDataColumn, String> {
|
||||
|
||||
List<MetaDataColumn> findByTable(MetaDataTable table);
|
||||
|
||||
@Query("select m from MetaDataColumn m " +
|
||||
"where lower(m.columnName) like lower(concat('%', :searchTerm, '%')) or lower(m.columnLabel) like lower(concat('%', :searchTerm, '%'))")
|
||||
List<MetaDataColumn> search(@Param("searchTerm") String searchTerm);
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.MetaDataTable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MetaDataTableRepository extends JpaRepository<MetaDataTable, String> {
|
||||
|
||||
MetaDataTable findByTableName(String tableName);
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.ModuleData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ModuleDataRepository extends JpaRepository<ModuleData, String> {
|
||||
|
||||
@Query("select m from ModuleData m where lower(m.moduleName) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<ModuleData> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
ModuleData findByModuleName(String moduleName);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface RoleRepository extends JpaRepository<Role, String> {
|
||||
|
||||
@Query("select r from Role r " +
|
||||
"where lower(r.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Role> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
@Query("select r from Role r " +
|
||||
"where lower(r.name) like lower(:name) ")
|
||||
Role findByName(@Param("name") String name);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, String> {
|
||||
|
||||
@Query("select u from User u " +
|
||||
"where lower(u.lastName) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<User> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
User findByUserName(String userName);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package de.thpeetz.kontor.admin.services;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.repository.AuthorizationMatrixRepository;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.repository.RoleRepository;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import de.thpeetz.kontor.admin.repository.UserRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AdminService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
private final AuthorizationMatrixRepository authorizationMatrixRepository;
|
||||
|
||||
public AdminService(UserRepository userRepository, RoleRepository roleRepository,
|
||||
AuthorizationMatrixRepository authorizationMatrixRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
this.authorizationMatrixRepository = authorizationMatrixRepository;
|
||||
}
|
||||
|
||||
public List<User> findAllUsers() {
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Role> findAllRoles() {
|
||||
return roleRepository.findAll();
|
||||
}
|
||||
|
||||
public Collection<Role> findAllRoles(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return roleRepository.findAll();
|
||||
} else {
|
||||
return roleRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public Role addRole(String roleName) {
|
||||
Role role = roleRepository.findByName(roleName);
|
||||
if (role == null) {
|
||||
log.info("Role {} was not found, will create it.", roleName);
|
||||
role = new Role();
|
||||
role.setName(roleName);
|
||||
roleRepository.save(role);
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
public void saveRole(Role role) {
|
||||
if (role == null) {
|
||||
log.warn("Role is null. Can't save it.");
|
||||
}
|
||||
log.info("saveRole: role={}", role);
|
||||
roleRepository.save(role);
|
||||
}
|
||||
|
||||
public void deleteRole(Role role) {
|
||||
if (role == null) {
|
||||
log.warn("Role is null. Can't delete it.");
|
||||
}
|
||||
log.info("deleteRole: role={}", role);
|
||||
roleRepository.delete(role);
|
||||
}
|
||||
|
||||
public List<AuthorizationMatrix> findAllAuthorizationMatrices() {
|
||||
return authorizationMatrixRepository.findAll();
|
||||
}
|
||||
|
||||
public void saveAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
|
||||
if (authorizationMatrix == null) {
|
||||
log.warn("AuthorizationMatrix is null. Can't save it.");
|
||||
}
|
||||
log.info("saveAuthorizationMatrix: authorizationMatrix={}", authorizationMatrix);
|
||||
authorizationMatrixRepository.save(authorizationMatrix);
|
||||
}
|
||||
|
||||
public void deleteAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
|
||||
if (authorizationMatrix == null) {
|
||||
log.warn("AuthorizationMatrix is null. Can't delete it.");
|
||||
}
|
||||
log.info("deleteAuthorizationMatrix: authorizationMatrix={}", authorizationMatrix);
|
||||
authorizationMatrixRepository.delete(authorizationMatrix);
|
||||
}
|
||||
|
||||
public String getUserFullName(String userName) {
|
||||
log.debug("get Fullname für user {}", userName);
|
||||
User user = userRepository.findByUserName(userName);
|
||||
if (user == null) {
|
||||
log.info("keinen Eintrag für {} gefunden", userName);
|
||||
return userName;
|
||||
} else {
|
||||
log.info("Voller Name des User {}: {}", userName, user.getFullName());
|
||||
return user.getFullName();
|
||||
}
|
||||
}
|
||||
|
||||
public User getUser(String userName) {
|
||||
log.debug("get User {}", userName);
|
||||
return userRepository.findByUserName(userName);
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
package de.thpeetz.kontor.admin.services;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.*;
|
||||
import de.thpeetz.kontor.admin.repository.AuthorizationMatrixRepository;
|
||||
import de.thpeetz.kontor.admin.repository.RoleRepository;
|
||||
import de.thpeetz.kontor.admin.repository.UserRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service("userDetailsService")
|
||||
public class KontorUserDetailsService implements UserDetailsService {
|
||||
|
||||
private static SecureRandom random = new SecureRandom();
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private AuthorizationMatrixRepository authorizationMatrixRepository;
|
||||
|
||||
public Collection<User> findAllUsers(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return userRepository.findAll();
|
||||
} else {
|
||||
return userRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveUser(User user) {
|
||||
if (user == null) {
|
||||
log.warn("User is null. Can't save it.");
|
||||
}
|
||||
log.info("saveUser: user={}", user);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
public void saveUser(User user, List<Role> roles) {
|
||||
if (user == null) {
|
||||
log.warn("User is null. Can't save it.");
|
||||
}
|
||||
log.info("First save user: {}", user);
|
||||
user = userRepository.save(user);
|
||||
List<Role> copy = roles.stream().collect(Collectors.toList());
|
||||
List<AuthorizationMatrix> permissions = user.getMatrix();
|
||||
permissions.forEach(matrix -> {
|
||||
if (roles.contains(matrix.getRole())) {
|
||||
log.info("Role {} already assigned", matrix.getRole());
|
||||
copy.remove(matrix.getRole());
|
||||
} else {
|
||||
log.info("Role {} has to be removed", matrix.getRole());
|
||||
authorizationMatrixRepository.delete(matrix);
|
||||
}
|
||||
});
|
||||
log.info("remaining roles: {}", copy);
|
||||
for (Role role : copy) {
|
||||
AuthorizationMatrix matrix = new AuthorizationMatrix();
|
||||
matrix.setUser(user);
|
||||
matrix.setRole(role);
|
||||
authorizationMatrixRepository.save(matrix);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteUser(User user) {
|
||||
if (user == null) {
|
||||
log.warn("User is null. Can't delete it.");
|
||||
}
|
||||
log.info("deleteUser: user={}", user);
|
||||
userRepository.delete(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
|
||||
|
||||
log.info("loadUserByUsername: userName={}", userName);
|
||||
User user = userRepository.findByUserName(userName);
|
||||
if (user == null) {
|
||||
log.info("User not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<? extends GrantedAuthority> authorities = getAuthorities(user);
|
||||
log.info("User {} hat Rolen: {}", userName, authorities);
|
||||
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(),
|
||||
authorities);
|
||||
}
|
||||
|
||||
private Collection<? extends GrantedAuthority> getAuthorities(User user) {
|
||||
return authorizationMatrixRepository.findByUser(user).stream()
|
||||
.map(matrix -> matrix.getRole().getName())
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String getRememberedUser(String id) {
|
||||
log.info("getRememberedUser: id={}", id);
|
||||
return "admin";
|
||||
}
|
||||
|
||||
public String rememberUser(String username) {
|
||||
String randomId = new BigInteger(130, random).toString(32);
|
||||
log.info("rememberUser: username={}", username);
|
||||
return randomId;
|
||||
}
|
||||
|
||||
public void removeRememberedUser(String id) {
|
||||
log.info("removeRememberedUser: id={}", id);
|
||||
}
|
||||
|
||||
public List<Role> findAllRoles() {
|
||||
return roleRepository.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.thpeetz.kontor.admin.services;
|
||||
|
||||
import de.thpeetz.kontor.mailclient.data.MailAccount;
|
||||
import de.thpeetz.kontor.admin.repository.MailAccountRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MailService {
|
||||
|
||||
private final MailAccountRepository mailAccountRepository;
|
||||
|
||||
public MailService(MailAccountRepository mailAccountRepository) {
|
||||
this.mailAccountRepository = mailAccountRepository;
|
||||
}
|
||||
|
||||
public List<MailAccount> findAllMailAccounts() {
|
||||
return mailAccountRepository.findAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package de.thpeetz.kontor.admin.services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.MetaDataColumn;
|
||||
import de.thpeetz.kontor.admin.repository.MetaDataColumnRepository;
|
||||
import de.thpeetz.kontor.admin.data.MetaDataTable;
|
||||
import de.thpeetz.kontor.admin.repository.MetaDataTableRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MetaDataService {
|
||||
|
||||
private final MetaDataTableRepository metaDataTableRepository;
|
||||
|
||||
private final MetaDataColumnRepository metaDataColumnRepository;
|
||||
|
||||
public MetaDataService(MetaDataTableRepository metaDataTableRepository, MetaDataColumnRepository metaDataColumnRepository) {
|
||||
this.metaDataTableRepository = metaDataTableRepository;
|
||||
this.metaDataColumnRepository = metaDataColumnRepository;
|
||||
}
|
||||
|
||||
public List<MetaDataTable> findAllTables() {
|
||||
return metaDataTableRepository.findAll();
|
||||
}
|
||||
|
||||
public MetaDataTable getTable(String tableName) {
|
||||
MetaDataTable table = metaDataTableRepository.findByTableName(tableName);
|
||||
if (table == null) {
|
||||
log.info("Metadata for table {} not found, will create it", tableName);
|
||||
table = new MetaDataTable();
|
||||
table.setTableName(tableName);
|
||||
metaDataTableRepository.save(table);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private void deleteTable(MetaDataTable metaDataTable) {
|
||||
List<MetaDataColumn> columns = metaDataTable.getTableColumns();
|
||||
List<MetaDataColumn> columnsToDelete = new LinkedList<>();
|
||||
for (MetaDataColumn column: columns) {
|
||||
try {
|
||||
columnsToDelete.add(column);
|
||||
metaDataColumnRepository.delete(column);
|
||||
} catch (Exception e) {
|
||||
log.info("Exception {} thrown, just go on", e.getMessage());
|
||||
}
|
||||
}
|
||||
for (MetaDataColumn column: columnsToDelete) {
|
||||
metaDataTable.getTableColumns().remove(column);
|
||||
}
|
||||
try {
|
||||
metaDataTableRepository.delete(metaDataTable);
|
||||
} catch (Exception e) {
|
||||
log.info("could not delete MetaDataTable: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void getColumn(MetaDataTable table, String columnName, String columnSyncName, String columnType, String columnModifier, Integer columnOrder, Boolean isShown, String columnLabel, Boolean showFilter, String filterLabel) {
|
||||
this.getColumn(table, columnName, columnSyncName, columnType, columnModifier, columnOrder, isShown, columnLabel, showFilter, filterLabel, null);
|
||||
}
|
||||
|
||||
public void getColumn(MetaDataTable table, String columnName, String columnSyncName, String columnType, String columnModifier, Integer columnOrder, Boolean isShown, String columnLabel, Boolean showFilter, String filterLabel, String refColumn) {
|
||||
if (table.getTableColumns().stream().anyMatch(column -> column.getColumnName().equals(columnName))) {
|
||||
log.debug("Column {} with name {} of table {} found, check Values", columnOrder, columnName, table.getTableName());
|
||||
MetaDataColumn column = table.getTableColumns().get(columnOrder.intValue()-1);
|
||||
if (!column.getColumnName().equals(columnName)) {
|
||||
log.debug("columnName has to be changed to {}", columnName);
|
||||
column.setColumnName(columnName);
|
||||
}
|
||||
if (!column.getColumnSyncName().equals(columnSyncName)) {
|
||||
log.debug("columnSyncName has to be changed to {}", columnSyncName);
|
||||
column.setColumnSyncName(columnSyncName);
|
||||
}
|
||||
if (!column.getColumnType().equals(columnType)) {
|
||||
log.debug("columnType has to be changed to {}", columnType);
|
||||
column.setColumnType(columnType);
|
||||
}
|
||||
if (columnModifier != null && !columnModifier.equals(column.getColumnModifier())) {
|
||||
log.debug("columnModifier has to be changed to {}", columnModifier);
|
||||
column.setColumnModifier(columnModifier);
|
||||
}
|
||||
if (isShown != null && !isShown.equals(column.getIsShown())) {
|
||||
log.debug("isShown has to be change to {}}", isShown);
|
||||
column.setIsShown(isShown);
|
||||
}
|
||||
if (columnLabel != null && !columnLabel.equals(column.getColumnLabel())) {
|
||||
log.debug("columnLabel has to be change to {}}", columnLabel);
|
||||
column.setColumnLabel(columnLabel);
|
||||
}
|
||||
if (showFilter != null &&!showFilter.equals(column.getShowFilter())) {
|
||||
log.debug("showFilter has to be change to {}}", showFilter);
|
||||
column.setShowFilter(showFilter);
|
||||
}
|
||||
if (filterLabel != null && !filterLabel.equals(column.getFilterLabel())) {
|
||||
log.debug("filterLabel has to be change to {}}", filterLabel);
|
||||
column.setFilterLabel(filterLabel);
|
||||
}
|
||||
if (refColumn != null && !refColumn.equals(column.getRefColumn())) {
|
||||
log.debug("refColumn has to be change to {}}", filterLabel);
|
||||
column.setRefColumn(refColumn);
|
||||
}
|
||||
metaDataColumnRepository.save(column);
|
||||
} else {
|
||||
log.info("Column {} of table {} not found, will create it", columnName, table.getTableName());
|
||||
MetaDataColumn column = new MetaDataColumn();
|
||||
column.setTable(table);
|
||||
column.setColumnName(columnName);
|
||||
column.setColumnSyncName(columnSyncName);
|
||||
column.setColumnType(columnType);
|
||||
column.setColumnModifier(columnModifier);
|
||||
column.setColumnOrder(columnOrder);
|
||||
column.setIsShown(Boolean.FALSE);
|
||||
metaDataColumnRepository.save(column);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<MetaDataColumn> findAllMetaDataColumns(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
log.debug("Found " + metaDataColumnRepository.count()+ " entries");
|
||||
return metaDataColumnRepository.findAll();
|
||||
} else {
|
||||
List<MetaDataColumn> results = metaDataColumnRepository.search(stringFilter);
|
||||
log.debug("Found " + results.size() + " entries");
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteMetaDataColumn(MetaDataColumn metaDataColumn) {
|
||||
if (metaDataColumn == null) {
|
||||
log.warn("MetaDataColumn is null, can't delete it");
|
||||
return;
|
||||
}
|
||||
log.debug("deleteMetaDataColumn: MetaDataColumn={}", metaDataColumn);
|
||||
metaDataColumnRepository.delete(metaDataColumn);
|
||||
}
|
||||
|
||||
public void saveMetaDataColumn(MetaDataColumn metaDataColumn) {
|
||||
if (metaDataColumn == null) {
|
||||
log.warn("MetaDataColumn is null, can't save it");
|
||||
return;
|
||||
}
|
||||
log.debug("saveMetaDataColumn: MetaDataColumn={}", metaDataColumn);
|
||||
metaDataColumnRepository.save(metaDataColumn);
|
||||
}
|
||||
|
||||
public String importTableData(Map<String, String> fields) {
|
||||
AtomicReference<String> status = new AtomicReference<>("unknown");
|
||||
String id = fields.get("id");
|
||||
Optional<MetaDataTable> optional = metaDataTableRepository.findById(id);
|
||||
if (optional.isEmpty()) {
|
||||
log.info(" not found: {} with {}", id, fields);
|
||||
status.set(id + "not found");
|
||||
MetaDataTable checkExisting = metaDataTableRepository.findByTableName(fields.get("table_name"));
|
||||
if (checkExisting != null) {
|
||||
log.info("entry already there with different id ({}), will be deleted", checkExisting.getId());
|
||||
deleteTable(checkExisting);
|
||||
}
|
||||
MetaDataTable metaDataTable = new MetaDataTable();
|
||||
metaDataTable.setId(id);
|
||||
metaDataTable.setTableName(fields.get("table_name"));
|
||||
metaDataTableRepository.save(metaDataTable);
|
||||
} else {
|
||||
optional.ifPresent( entry -> {
|
||||
log.info(" found: {}", entry.getTableName());
|
||||
String updateStatus = updateTableFields(entry, fields);
|
||||
metaDataTableRepository.save(entry);
|
||||
status.set(updateStatus);
|
||||
});
|
||||
}
|
||||
return status.get();
|
||||
}
|
||||
|
||||
public String importColumnData(String tableName, Map<String, String> fields) {
|
||||
AtomicReference<String> status = new AtomicReference<>("unknown");
|
||||
String id = fields.get("id");
|
||||
Optional<MetaDataColumn> optional = metaDataColumnRepository.findById(id);
|
||||
if (optional.isEmpty()) {
|
||||
log.info(" not found: {} with {}", id, fields);
|
||||
status.set(id + "not found");
|
||||
MetaDataColumn metaDataColumn = new MetaDataColumn();
|
||||
metaDataColumn.setId(id);
|
||||
metaDataColumn.setColumnName(fields.get("column_name"));
|
||||
metaDataColumn.setColumnSyncName(fields.get("column_sync_name"));
|
||||
metaDataColumn.setColumnType(fields.get("column_type"));
|
||||
metaDataColumnRepository.save(metaDataColumn);
|
||||
} else {
|
||||
optional.ifPresent( entry -> {
|
||||
log.info(" found: {}", entry.getTableName());
|
||||
String updateStatus = updateColumnFields(entry, tableName, fields);
|
||||
metaDataColumnRepository.save(entry);
|
||||
status.set(updateStatus);
|
||||
});
|
||||
}
|
||||
return status.get();
|
||||
}
|
||||
|
||||
private String updateColumnFields(MetaDataColumn metaDataColumn, String tableName, Map<String, String> fields) {
|
||||
StringBuilder status = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : fields.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
switch (key) {
|
||||
case "id", "created_date", "last_modified_date", "version":
|
||||
break;
|
||||
case "column_name":
|
||||
status.append(metaDataColumn.updateColumnName(value));
|
||||
break;
|
||||
case "column_sync_name":
|
||||
status.append(metaDataColumn.updateColumnSyncName(value));
|
||||
break;
|
||||
default:
|
||||
log.info("field {} is unknown for table {}", key, tableName);
|
||||
}
|
||||
}
|
||||
return status.toString();
|
||||
}
|
||||
|
||||
private String updateTableFields(MetaDataTable metaDataTable, Map<String, String> fields) {
|
||||
String status = "";
|
||||
for (Map.Entry<String, String> entry : fields.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
switch (key) {
|
||||
case "id", "created_date", "last_modified_date", "version":
|
||||
break;
|
||||
case "table_name":
|
||||
status += metaDataTable.updateTableName(value);
|
||||
default:
|
||||
log.info("field {} is unknown for table {}", key, MetaDataTable.class.getName());
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package de.thpeetz.kontor.admin.services;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.ModuleData;
|
||||
import de.thpeetz.kontor.admin.repository.ModuleDataRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ModuleService {
|
||||
|
||||
private final ModuleDataRepository moduleDataRepository;
|
||||
|
||||
public ModuleService(ModuleDataRepository moduleDataRepository) {
|
||||
this.moduleDataRepository = moduleDataRepository;
|
||||
}
|
||||
|
||||
public List<ModuleData> findAll(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return moduleDataRepository.findAll();
|
||||
} else {
|
||||
return moduleDataRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public ModuleData findByName(String moduleName) {
|
||||
if (moduleName == null || moduleName.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return moduleDataRepository.findByModuleName(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean importData(String moduleName) {
|
||||
ModuleData module = moduleDataRepository.findByModuleName(moduleName);
|
||||
if (module != null) {
|
||||
return module.getImportData();
|
||||
} else {
|
||||
log.info("Module {} not found, should import data", moduleName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDataImported(String moduleName) {
|
||||
ModuleData module = moduleDataRepository.findByModuleName(moduleName);
|
||||
if (module == null) {
|
||||
log.info("Module {} not found, will create it", moduleName);
|
||||
module = new ModuleData();
|
||||
module.setModuleName(moduleName);
|
||||
module.setImportData(false);
|
||||
moduleDataRepository.save(module);
|
||||
} else {
|
||||
log.info("Module {} found, change import data", module);
|
||||
module.setImportData(false);
|
||||
moduleDataRepository.save(module);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveModuleData(ModuleData moduleData) {
|
||||
if (moduleData == null) {
|
||||
log.warn("ModuleData is null, can't save it.");
|
||||
} else {
|
||||
moduleDataRepository.save(moduleData);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteModuleData(ModuleData moduleData) {
|
||||
if (moduleData == null) {
|
||||
log.warn("ModuleData is null, can't delete it.");
|
||||
} else {
|
||||
moduleDataRepository.delete(moduleData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
|
||||
import de.thpeetz.kontor.admin.AdminConstants;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.common.views.KontorLayoutUtil;
|
||||
import de.thpeetz.kontor.security.SecurityService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class AdminLayout extends AppLayout {
|
||||
|
||||
private final AdminService adminService;
|
||||
|
||||
private final SecurityService securityService;
|
||||
|
||||
public AdminLayout(AdminService adminService, SecurityService securityService) {
|
||||
this.adminService = adminService;
|
||||
this.securityService = securityService;
|
||||
|
||||
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService);
|
||||
layout.setSecondaryNavigation(getSecondaryNavigation());
|
||||
layout.createHeader(AdminConstants.ADMIN_TITLE);
|
||||
}
|
||||
|
||||
private HorizontalLayout getSecondaryNavigation() {
|
||||
HorizontalLayout navigation = new HorizontalLayout();
|
||||
navigation.addClassNames(LumoUtility.JustifyContent.CENTER, LumoUtility.Gap.SMALL, LumoUtility.Height.MEDIUM);
|
||||
navigation.add(AdminConstants.getUserNavigation(), AdminConstants.getRoleNavigation(),
|
||||
AdminConstants.getAuthorizationNavigation());
|
||||
return navigation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class AuthorizationForm extends FormLayout {
|
||||
|
||||
ComboBox<User> user = new ComboBox<>("User");
|
||||
ComboBox<Role> role = new ComboBox<>("Role");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<AuthorizationMatrix> binder = new BeanValidationBinder<>(AuthorizationMatrix.class);
|
||||
|
||||
public AuthorizationForm(List<User> users, List<Role> roles) {
|
||||
addClassName("authorizationmatrix-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
user.setItems(users);
|
||||
user.setItemLabelGenerator(User::getUserName);
|
||||
role.setItems(roles);
|
||||
role.setItemLabelGenerator(Role::getName);
|
||||
add(user, role, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
|
||||
binder.setBean(authorizationMatrix);
|
||||
}
|
||||
|
||||
public abstract static class AuthorizationFormEvent extends ComponentEvent<AuthorizationForm> {
|
||||
private AuthorizationMatrix authorizationMatrix;
|
||||
|
||||
protected AuthorizationFormEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
|
||||
super(source, false);
|
||||
this.authorizationMatrix = authorizationMatrix;
|
||||
}
|
||||
|
||||
public AuthorizationMatrix getAuthorizationMatrix() {
|
||||
return authorizationMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends AuthorizationFormEvent {
|
||||
SaveEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
|
||||
super(source, authorizationMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends AuthorizationFormEvent {
|
||||
DeleteEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
|
||||
super(source, authorizationMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends AuthorizationFormEvent {
|
||||
CloseEvent(AuthorizationForm 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,114 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.admin.AdminConstants;
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = AdminConstants.AUTHORIZATION_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Authorization | Admin | Kontor")
|
||||
public class AuthorizationView extends VerticalLayout {
|
||||
|
||||
Grid<AuthorizationMatrix> grid = new Grid<>(AuthorizationMatrix.class);
|
||||
AuthorizationForm form;
|
||||
AdminService service;
|
||||
|
||||
public AuthorizationView(AdminService service) {
|
||||
this.service = service;
|
||||
addClassName("authoriaztionmatrix-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("authorizationmatrix-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("user.userName", "role.name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editAuthorizationMatrix(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new AuthorizationForm(service.findAllUsers(), service.findAllRoles());
|
||||
form.setWidth("25em");
|
||||
form.addSaveListener(this::saveAuthorizationMatrix);
|
||||
form.addDeleteListener(this::deleteAuthorizationMatrix);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveAuthorizationMatrix(AuthorizationForm.SaveEvent event) {
|
||||
AuthorizationMatrix authorizationMatrix = event.getAuthorizationMatrix();
|
||||
service.saveAuthorizationMatrix(authorizationMatrix);
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteAuthorizationMatrix(AuthorizationForm.DeleteEvent event) {
|
||||
service.deleteAuthorizationMatrix(event.getAuthorizationMatrix());
|
||||
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() {
|
||||
Button addAuthorizationMaxtrixButton = new Button("Add permssion", click -> addAuthorizationMatrix());
|
||||
HorizontalLayout toolbar = new HorizontalLayout(addAuthorizationMaxtrixButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
|
||||
if (authorizationMatrix == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setAuthorizationMatrix(authorizationMatrix);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setAuthorizationMatrix(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addAuthorizationMatrix() {
|
||||
grid.asSingleSelect().clear();
|
||||
editAuthorizationMatrix(new AuthorizationMatrix());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllAuthorizationMatrices());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import com.vaadin.flow.component.html.H1;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.login.LoginForm;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.router.BeforeEnterEvent;
|
||||
import com.vaadin.flow.router.BeforeEnterObserver;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.server.auth.AnonymousAllowed;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Route("login")
|
||||
@PageTitle("Login | Vaadin Kontor")
|
||||
@AnonymousAllowed
|
||||
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
|
||||
|
||||
private final LoginForm login = new LoginForm();
|
||||
|
||||
public LoginView() {
|
||||
addClassName("login-view");
|
||||
setSizeFull();
|
||||
setAlignItems(Alignment.CENTER);
|
||||
setJustifyContentMode(JustifyContentMode.CENTER);
|
||||
|
||||
login.setAction("login");
|
||||
|
||||
add(new H1("Vaadin Kontor"));
|
||||
add(new Span("Username: user, Password: password"));
|
||||
add(new Span("Username: admin, Password: password"));
|
||||
add(login);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
|
||||
log.info("beforeEnter: {}", beforeEnterEvent.getLocation());
|
||||
log.info("beforeEnter: {}", SecurityContextHolder.getContext().getAuthentication());
|
||||
// inform the user about an authentication error
|
||||
if (beforeEnterEvent.getLocation()
|
||||
.getQueryParameters()
|
||||
.getParameters()
|
||||
.containsKey("error")) {
|
||||
login.setError(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
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.admin.data.MetaDataColumn;
|
||||
import de.thpeetz.kontor.admin.data.MetaDataTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MetaDataForm extends FormLayout {
|
||||
|
||||
ComboBox<MetaDataTable> table = new ComboBox<>("Table");
|
||||
TextField columnName = new TextField("Column Name");
|
||||
TextField columnSyncName = new TextField("Column Sync Name");
|
||||
TextField columnModifier = new TextField("Column Modifier");
|
||||
IntegerField columnOrder = new IntegerField("Column Order");
|
||||
Checkbox isShown = new Checkbox("Is Shown");
|
||||
TextField columnLabel = new TextField("Column Label");
|
||||
Checkbox showFilter = new Checkbox("Show Filter");
|
||||
TextField filterLabel = new TextField("Filter Label");
|
||||
TextField refColumn = new TextField("Ref Column");
|
||||
|
||||
Button save = new com.vaadin.flow.component.button.Button("Save");
|
||||
Button delete = new com.vaadin.flow.component.button.Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<MetaDataColumn> binder = new BeanValidationBinder<>(MetaDataColumn.class);
|
||||
|
||||
public MetaDataForm(List<MetaDataTable> tables) {
|
||||
addClassName("metaData-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
table.setItems(tables);
|
||||
table.setItemLabelGenerator(MetaDataTable::getTableName);
|
||||
add(table, columnName, columnSyncName, columnModifier, columnOrder);
|
||||
add(isShown, columnLabel);
|
||||
isShown.addClickListener(click -> columnLabel.setEnabled(isShown.getValue()));
|
||||
add(showFilter, filterLabel);
|
||||
showFilter.addClickListener(click -> filterLabel.setEnabled(showFilter.getValue()));
|
||||
add(refColumn);
|
||||
add(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 MetaDataForm.DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new MetaDataForm.CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new MetaDataForm.SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setMetaDataColumn(MetaDataColumn metaDataColumn) {
|
||||
binder.setBean(metaDataColumn);
|
||||
}
|
||||
|
||||
public abstract static class MetaDataFormEvent extends ComponentEvent<MetaDataForm> {
|
||||
private MetaDataColumn metaDataColumn;
|
||||
|
||||
protected MetaDataFormEvent(MetaDataForm source, MetaDataColumn metaDataColumn) {
|
||||
super(source, false);
|
||||
this.metaDataColumn = metaDataColumn;
|
||||
}
|
||||
|
||||
public MetaDataColumn getMetaDataColumn() {
|
||||
return metaDataColumn;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends MetaDataForm.MetaDataFormEvent {
|
||||
SaveEvent(MetaDataForm source, MetaDataColumn metaDataColumn) {
|
||||
super(source, metaDataColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends MetaDataForm.MetaDataFormEvent {
|
||||
DeleteEvent(MetaDataForm source, MetaDataColumn metaDataColumn) {
|
||||
super(source, metaDataColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends MetaDataForm.MetaDataFormEvent {
|
||||
CloseEvent(MetaDataForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<MetaDataForm.DeleteEvent> listener) {
|
||||
addListener(MetaDataForm.DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<MetaDataForm.SaveEvent> listener) {
|
||||
addListener(MetaDataForm.SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<MetaDataForm.CloseEvent> listener) {
|
||||
addListener(MetaDataForm.CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.contextmenu.ContextMenu;
|
||||
import com.vaadin.flow.component.contextmenu.MenuItem;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.grid.GridSortOrder;
|
||||
import com.vaadin.flow.component.icon.Icon;
|
||||
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.provider.SortDirection;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import de.thpeetz.kontor.admin.AdminConstants;
|
||||
import de.thpeetz.kontor.admin.data.MetaDataColumn;
|
||||
import de.thpeetz.kontor.admin.services.MetaDataService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import de.thpeetz.kontor.common.views.ColumnToggleContextMenu;
|
||||
import de.thpeetz.kontor.common.views.StatusIcon;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = AdminConstants.METADATA_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Meta Data | Admin | Kontor")
|
||||
public class MetaDataView extends VerticalLayout {
|
||||
|
||||
Grid<MetaDataColumn> grid = new Grid<>(MetaDataColumn.class, false);
|
||||
Grid.Column<MetaDataColumn> idColumn = grid.addColumn(MetaDataColumn::getId)
|
||||
.setHeader("ID").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> createdColumn = grid.addColumn(MetaDataColumn::getCreatedDate)
|
||||
.setHeader("Erstellt").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> modifiedColumn = grid.addColumn(MetaDataColumn::getLastModifiedDate)
|
||||
.setHeader("Geändert").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> versionColumn = grid.addColumn(MetaDataColumn::getVersion)
|
||||
.setHeader("Version").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> tableColumn = grid.addColumn(MetaDataColumn::getTableName)
|
||||
.setHeader("Table").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> columnNameColumn = grid.addColumn(MetaDataColumn::getColumnName)
|
||||
.setHeader("Column Name").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> columnSyncNameColumn = grid.addColumn(MetaDataColumn::getColumnSyncName)
|
||||
.setHeader("Column Sync Name").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> columnTypeColumn = grid.addColumn(MetaDataColumn::getColumnType)
|
||||
.setHeader("Column Type").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> columnModifierColumn = grid.addColumn(MetaDataColumn::getColumnModifier)
|
||||
.setHeader("Column Modifier").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> columnOrderColumn = grid.addColumn(MetaDataColumn::getColumnOrder)
|
||||
.setHeader("Column Order").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> isShownColumn = grid.addComponentColumn(metaDataColumn -> StatusIcon.create(metaDataColumn.getIsShown())).
|
||||
setHeader("Anzeige?").setWidth("6rem").setSortable(true);
|
||||
Grid.Column<MetaDataColumn> columnLabelColumn = grid.addColumn(MetaDataColumn::getColumnLabel)
|
||||
.setHeader("Spaltenname").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> showFilterColumn = grid.addComponentColumn(metaDataColumn -> StatusIcon.create(metaDataColumn.getShowFilter())).
|
||||
setHeader("Zeige Filter").setWidth("6rem").setSortable(true);
|
||||
Grid.Column<MetaDataColumn> filterLabelColumn = grid.addColumn(MetaDataColumn::getFilterLabel)
|
||||
.setHeader("Filter Name").setResizable(true).setSortable(true);
|
||||
Grid.Column<MetaDataColumn> refColumnColumn = grid.addColumn(MetaDataColumn::getRefColumn)
|
||||
.setHeader("Ref Column Name").setResizable(true).setSortable(true);
|
||||
TextField searchField = new TextField();
|
||||
@Getter
|
||||
MetaDataForm form;
|
||||
MetaDataService service;
|
||||
|
||||
public MetaDataView(MetaDataService service) {
|
||||
this.service = service;
|
||||
addClassName("metadata-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("metadata-grid");
|
||||
grid.setSizeFull();
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
idColumn.setVisible(false);
|
||||
createdColumn.setVisible(false);
|
||||
modifiedColumn.setVisible(false);
|
||||
versionColumn.setVisible(false);
|
||||
grid.setMultiSort(true);
|
||||
List<GridSortOrder<MetaDataColumn>> sortOrder = new ArrayList<>();
|
||||
sortOrder.add(new GridSortOrder<MetaDataColumn>(tableColumn, SortDirection.ASCENDING));
|
||||
sortOrder.add(new GridSortOrder<MetaDataColumn>(columnOrderColumn, SortDirection.ASCENDING));
|
||||
grid.sort(sortOrder);
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editMetaData(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new MetaDataForm(service.findAllTables());
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveMetaData);
|
||||
form.addDeleteListener(this::deleteMetaData);
|
||||
form.addCloseListener(e -> 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() {
|
||||
searchField.setPlaceholder("Search");
|
||||
searchField.setClearButtonVisible(true);
|
||||
searchField.setPrefixComponent(new Icon(VaadinIcon.SEARCH));
|
||||
searchField.setValueChangeMode(ValueChangeMode.EAGER);
|
||||
searchField.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addMetaDataButton = new Button("Add Meta Data");
|
||||
addMetaDataButton.addClickListener(click -> addMetaDataColumn());
|
||||
|
||||
Button menuButton = new Button("Show/Hide Columns");
|
||||
menuButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
ColumnToggleContextMenu<MetaDataColumn> columnToggleContextMenu = new ColumnToggleContextMenu<>(menuButton);
|
||||
columnToggleContextMenu.addColumnToggleItem(idColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(createdColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(modifiedColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(versionColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(tableColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(columnNameColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(columnSyncNameColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(columnTypeColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(columnModifierColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(columnOrderColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(isShownColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(columnLabelColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(showFilterColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(filterLabelColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(refColumnColumn);
|
||||
HorizontalLayout toolbar = new HorizontalLayout(searchField, addMetaDataButton, menuButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
private void saveMetaData(MetaDataForm.SaveEvent event) {
|
||||
MetaDataColumn metaDataColumn = event.getMetaDataColumn();
|
||||
service.saveMetaDataColumn(metaDataColumn);
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteMetaData(MetaDataForm.DeleteEvent event) {
|
||||
service.deleteMetaDataColumn(event.getMetaDataColumn());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
public void editMetaData(MetaDataColumn metaDataColumn) {
|
||||
if (metaDataColumn == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setMetaDataColumn(metaDataColumn);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setMetaDataColumn(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addMetaDataColumn() {
|
||||
grid.asSingleSelect().clear();
|
||||
editMetaData(new MetaDataColumn());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllMetaDataColumns(searchField.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.admin.data.ModuleData;
|
||||
|
||||
public class ModuleDataForm extends FormLayout {
|
||||
TextField moduleName = new TextField("Module Name");
|
||||
Checkbox importData = new Checkbox("Import Data");
|
||||
|
||||
Button save = new com.vaadin.flow.component.button.Button("Save");
|
||||
Button delete = new com.vaadin.flow.component.button.Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<ModuleData> binder = new BeanValidationBinder<>(ModuleData.class);
|
||||
|
||||
public ModuleDataForm() {
|
||||
addClassName("moduleData-form");
|
||||
binder.bindInstanceFields(this);
|
||||
add(moduleName, importData, 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 ModuleDataForm.DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new ModuleDataForm.CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new ModuleDataForm.SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setModuleData(ModuleData moduleData) {
|
||||
binder.setBean(moduleData);
|
||||
}
|
||||
|
||||
public abstract static class ModuleDataFormEvent extends ComponentEvent<ModuleDataForm> {
|
||||
private ModuleData moduleData;
|
||||
|
||||
protected ModuleDataFormEvent(ModuleDataForm source, ModuleData moduleData) {
|
||||
super(source, false);
|
||||
this.moduleData = moduleData;
|
||||
}
|
||||
|
||||
public ModuleData getModuleData() {
|
||||
return moduleData;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends ModuleDataForm.ModuleDataFormEvent {
|
||||
SaveEvent(ModuleDataForm source, ModuleData moduleData) {
|
||||
super(source, moduleData);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends ModuleDataForm.ModuleDataFormEvent {
|
||||
DeleteEvent(ModuleDataForm source, ModuleData moduleData) {
|
||||
super(source, moduleData);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends ModuleDataForm.ModuleDataFormEvent {
|
||||
CloseEvent(ModuleDataForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<ModuleDataForm.DeleteEvent> listener) {
|
||||
addListener(ModuleDataForm.DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<ModuleDataForm.SaveEvent> listener) {
|
||||
addListener(ModuleDataForm.SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<ModuleDataForm.CloseEvent> listener) {
|
||||
addListener(ModuleDataForm.CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.contextmenu.ContextMenu;
|
||||
import com.vaadin.flow.component.contextmenu.MenuItem;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.icon.Icon;
|
||||
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.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import de.thpeetz.kontor.admin.data.ModuleData;
|
||||
import de.thpeetz.kontor.admin.services.ModuleService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import de.thpeetz.kontor.common.views.ColumnToggleContextMenu;
|
||||
import de.thpeetz.kontor.common.views.StatusIcon;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = "admin/module", layout = MainLayout.class)
|
||||
@PageTitle("Module Data | Admin | Kontor")
|
||||
public class ModuleDataView extends VerticalLayout {
|
||||
|
||||
Grid<ModuleData> grid = new Grid<>(ModuleData.class, false);
|
||||
Grid.Column<ModuleData> idColumn = grid.addColumn(ModuleData::getId)
|
||||
.setHeader("ID").setResizable(true).setSortable(true);
|
||||
Grid.Column<ModuleData> nameColumn = grid.addColumn(ModuleData::getModuleName)
|
||||
.setHeader("Name").setResizable(true).setSortable(true);
|
||||
Grid.Column<ModuleData> importColumn = grid.addComponentColumn(moduleData -> StatusIcon.create(moduleData.getImportData()))
|
||||
.setHeader("Import Data").setWidth("6rem").setSortable(true);
|
||||
|
||||
TextField filterText = new TextField();
|
||||
@Getter
|
||||
ModuleDataForm form;
|
||||
ModuleService service;
|
||||
|
||||
public ModuleDataView(ModuleService service) {
|
||||
this.service = service;
|
||||
addClassName("moduleData-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("moduleData-grid");
|
||||
grid.setSizeFull();
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editModuleData(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new ModuleDataForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveModuleData);
|
||||
form.addDeleteListener(this::deleteModuleData);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveModuleData(ModuleDataForm.SaveEvent event) {
|
||||
ModuleData moduleData = event.getModuleData();
|
||||
service.saveModuleData(moduleData);
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteModuleData(ModuleDataForm.DeleteEvent event) {
|
||||
service.deleteModuleData(event.getModuleData());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by module name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
Button addModuleDataButton = new Button("Add module", click -> addModuleData());
|
||||
|
||||
Button menuButton = new Button("Show/Hide Columns");
|
||||
menuButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
ColumnToggleContextMenu<ModuleData> columnToggleContextMenu = new ColumnToggleContextMenu<>(menuButton);
|
||||
columnToggleContextMenu.addColumnToggleItem(idColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(nameColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(importColumn);
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addModuleDataButton, menuButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editModuleData(ModuleData moduleData) {
|
||||
if (moduleData == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setModuleData(moduleData);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setModuleData(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addModuleData() {
|
||||
grid.asSingleSelect().clear();
|
||||
editModuleData(new ModuleData());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAll(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.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.admin.data.Role;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class RoleForm extends FormLayout {
|
||||
|
||||
TextField name = new TextField("Role name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Role> binder = new BeanValidationBinder<>(Role.class);
|
||||
|
||||
public RoleForm() {
|
||||
addClassName("role-form");
|
||||
binder.bindInstanceFields(this);
|
||||
add(name, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setRole(Role role) {
|
||||
binder.setBean(role);
|
||||
}
|
||||
|
||||
public abstract static class RoleFormEvent extends ComponentEvent<RoleForm> {
|
||||
private Role role;
|
||||
|
||||
protected RoleFormEvent(RoleForm source, Role role) {
|
||||
super(source, false);
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends RoleFormEvent {
|
||||
SaveEvent(RoleForm source, Role role) {
|
||||
super(source, role);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends RoleFormEvent {
|
||||
DeleteEvent(RoleForm source, Role role) {
|
||||
super(source, role);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends RoleFormEvent {
|
||||
CloseEvent(RoleForm 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,118 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.admin.AdminConstants;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = AdminConstants.ROLE_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Rollen | Admin | Kontor")
|
||||
public class RoleView extends VerticalLayout {
|
||||
Grid<Role> grid = new Grid<>(Role.class);
|
||||
TextField filterText = new TextField();
|
||||
RoleForm form;
|
||||
AdminService service;
|
||||
|
||||
public RoleView(AdminService service) {
|
||||
this.service = service;
|
||||
addClassName("user-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("user-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editRole(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new RoleForm();
|
||||
form.setWidth("25em");
|
||||
form.addSaveListener(this::saveRole);
|
||||
form.addDeleteListener(this::deleteRole);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveRole(RoleForm.SaveEvent event) {
|
||||
service.saveRole(event.getRole());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteRole(RoleForm.DeleteEvent event) {
|
||||
service.deleteRole(event.getRole());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by user name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
Button addUserButton = new Button("Add user", click -> addUser());
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addUserButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editRole(Role role) {
|
||||
if (role == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setRole(role);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setRole(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addUser() {
|
||||
grid.asSingleSelect().clear();
|
||||
editRole(new Role());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllRoles(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.checkbox.CheckboxGroup;
|
||||
import com.vaadin.flow.component.checkbox.CheckboxGroupVariant;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.textfield.EmailField;
|
||||
import com.vaadin.flow.component.textfield.PasswordField;
|
||||
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.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class UserForm extends FormLayout {
|
||||
|
||||
TextField userName = new TextField("User name");
|
||||
PasswordField password = new PasswordField("Password");
|
||||
EmailField email = new EmailField("Email");
|
||||
TextField firstName = new TextField("First name");
|
||||
TextField lastName = new TextField("Last name");
|
||||
Checkbox enabled = new Checkbox("Enabled");
|
||||
String originalPassword;
|
||||
|
||||
CheckboxGroup<Role> permissions = new CheckboxGroup<>("Permissions");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<User> binder = new BeanValidationBinder<>(User.class);
|
||||
|
||||
public UserForm() {
|
||||
addClassName("user-form");
|
||||
binder.bindInstanceFields(this);
|
||||
add(userName, password, email, firstName, lastName, enabled, configurePermissionsGroup(), createButtonsLayout());
|
||||
}
|
||||
|
||||
private CheckboxGroup<Role> configurePermissionsGroup() {
|
||||
permissions.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
|
||||
permissions.setItemLabelGenerator(Role::getName);
|
||||
permissions.addValueChangeListener(event -> {
|
||||
log.debug("permissions changed: {}", event);
|
||||
});
|
||||
return permissions;
|
||||
}
|
||||
|
||||
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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
binder.setBean(user);
|
||||
//log.debug("UserForm.setUser: {}", user);
|
||||
if (user != null) {
|
||||
this.originalPassword = user.getPassword();
|
||||
} else {
|
||||
this.originalPassword = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setRoles(List<Role> roles, User user) {
|
||||
permissions.setItems(roles);
|
||||
user.getMatrix().stream().forEach(authorizationMatrix -> {
|
||||
permissions.select(authorizationMatrix.getRole());
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasPasswordChanged(User user) {
|
||||
return !originalPassword.equals(user.getPassword());
|
||||
}
|
||||
|
||||
public abstract static class UserFormEvent extends ComponentEvent<UserForm> {
|
||||
private User user;
|
||||
|
||||
protected UserFormEvent(UserForm source, User user) {
|
||||
super(source, false);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends UserFormEvent {
|
||||
SaveEvent(UserForm source, User user) {
|
||||
super(source, user);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends UserFormEvent {
|
||||
DeleteEvent(UserForm source, User user) {
|
||||
super(source, user);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends UserFormEvent {
|
||||
CloseEvent(UserForm 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,73 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
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.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 com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import de.thpeetz.kontor.security.SecurityService;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Route(value="user/profile", layout = MainLayout.class)
|
||||
@PermitAll
|
||||
@PageTitle("Profile | User | Kontor")
|
||||
public class UserProfileView extends VerticalLayout {
|
||||
|
||||
private SecurityService securityService;
|
||||
|
||||
private AdminService adminService;
|
||||
|
||||
TextField firstName = new TextField("First name");
|
||||
TextField lastName = new TextField("Last name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button close = new Button("Cancel");
|
||||
Binder<User> binder = new BeanValidationBinder<>(User.class);
|
||||
|
||||
public UserProfileView(AdminService adminService, SecurityService securityService) {
|
||||
this.adminService = adminService;
|
||||
this.securityService = securityService;
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
add(firstName, lastName, createButtonsLayout());
|
||||
securityService.getAuthenticatedUser().ifPresent(user -> {
|
||||
log.info("UserProfileView: {}", user.getUsername());
|
||||
binder.setBean(adminService.getUser(user.getUsername()));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private HorizontalLayout createButtonsLayout() {
|
||||
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
|
||||
save.addClickShortcut(Key.ENTER);
|
||||
close.addClickShortcut(Key.ESCAPE);
|
||||
|
||||
save.addClickListener(event -> validateAndSave());
|
||||
close.addClickListener(event -> closeView());
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
log.info("update user profile");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeView() {
|
||||
log.info("close user profile view");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import de.thpeetz.kontor.admin.services.KontorUserDetailsService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = "admin/user", layout = MainLayout.class)
|
||||
@PageTitle("User | Admin | Kontor")
|
||||
public class UserView extends VerticalLayout {
|
||||
|
||||
Grid<User> grid = new Grid<>(User.class);
|
||||
TextField filterText = new TextField();
|
||||
UserForm form;
|
||||
KontorUserDetailsService service;
|
||||
|
||||
@Autowired
|
||||
PasswordEncoder passwordEncoder;
|
||||
|
||||
public UserView(KontorUserDetailsService service) {
|
||||
this.service = service;
|
||||
addClassName("user-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("user-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("userName", "email", "firstName", "lastName", "enabled");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editUser(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new UserForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveUser);
|
||||
form.addDeleteListener(this::deleteUser);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveUser(UserForm.SaveEvent event) {
|
||||
User user = event.getUser();
|
||||
log.debug("UserView.saveUser: {}", user);
|
||||
List<Role> permissions = form.permissions.getSelectedItems().stream().collect(Collectors.toList());
|
||||
log.info("selected permissions: {}", permissions);
|
||||
if (form.hasPasswordChanged(user)) {
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
log.debug("password changed for user {}", user);
|
||||
}
|
||||
service.saveUser(user, permissions);
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteUser(UserForm.DeleteEvent event) {
|
||||
service.deleteUser(event.getUser());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by user name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
Button addUserButton = new Button("Add user", click -> addUser());
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addUserButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editUser(User user) {
|
||||
if (user == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setUser(user);
|
||||
form.setRoles(service.findAllRoles(), user);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setUser(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addUser() {
|
||||
grid.asSingleSelect().clear();
|
||||
editUser(new User());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllUsers(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package de.thpeetz.kontor.bookshelf;
|
||||
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.sidenav.SideNav;
|
||||
import com.vaadin.flow.component.sidenav.SideNavItem;
|
||||
import com.vaadin.flow.router.RouterLink;
|
||||
|
||||
import de.thpeetz.kontor.bookshelf.views.ArticleView;
|
||||
import de.thpeetz.kontor.bookshelf.views.AuthorView;
|
||||
import de.thpeetz.kontor.bookshelf.views.BookView;
|
||||
import de.thpeetz.kontor.bookshelf.views.BookshelfPublisherView;
|
||||
|
||||
public class BookshelfConstants {
|
||||
|
||||
public static final String AUTHOR = "Author";
|
||||
public static final String ARTICLE = "Article";
|
||||
public static final String BOOK = "Book";
|
||||
public static final String BOOKSHELF = "Bookshelf";
|
||||
public static final String PUBLISHER = "Publisher";
|
||||
public static final String PUBLISHER_ROUTE = "bookshelf/publisher";
|
||||
public static final String AUTHOR_ROUTE = "bookshelf/author";
|
||||
public static final String BOOK_ROUTE = "bookshelf/book";
|
||||
public static final String ARTICLE_ROUTE = "bookshelf/article";
|
||||
|
||||
public static RouterLink getPublisherLink() {
|
||||
return new RouterLink(PUBLISHER, BookshelfPublisherView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getAuthorLink() {
|
||||
return new RouterLink(AUTHOR, AuthorView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getBookLink() {
|
||||
return new RouterLink(BOOK, BookView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getArticleLink() {
|
||||
return new RouterLink(ARTICLE, ArticleView.class);
|
||||
}
|
||||
|
||||
public static SideNavItem getBookshelfNavigation() {
|
||||
SideNavItem bookshelf = new SideNavItem(BOOKSHELF, BookView.class, VaadinIcon.OPEN_BOOK.create());
|
||||
bookshelf.addItem(new SideNavItem(BOOK, BookView.class));
|
||||
bookshelf.addItem(new SideNavItem(PUBLISHER, BookshelfPublisherView.class));
|
||||
bookshelf.addItem(new SideNavItem(AUTHOR, AuthorView.class));
|
||||
bookshelf.addItem(new SideNavItem(ARTICLE, ArticleView.class));
|
||||
return bookshelf;
|
||||
}
|
||||
|
||||
private BookshelfConstants() {
|
||||
// private constructor to hide the implicit public one
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package de.thpeetz.kontor.bookshelf;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import de.thpeetz.kontor.admin.services.ModuleService;
|
||||
import de.thpeetz.kontor.bookshelf.data.ArticleAuthorRepository;
|
||||
import de.thpeetz.kontor.bookshelf.data.Author;
|
||||
import de.thpeetz.kontor.bookshelf.data.AuthorRepository;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookAuthorRepository;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookRepository;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookshelfPublisher;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookshelfPublisherRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SetupModuleBookshelf implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
boolean alreadySetup = false;
|
||||
|
||||
@Autowired
|
||||
private BookshelfPublisherRepository publisherRepository;
|
||||
|
||||
@Autowired
|
||||
private AuthorRepository authorRepository;
|
||||
|
||||
@Autowired
|
||||
private ArticleAuthorRepository articleAuthorRepository;
|
||||
|
||||
@Autowired
|
||||
private BookRepository bookRepository;
|
||||
|
||||
@Autowired
|
||||
private BookAuthorRepository bookAuthorRepository;
|
||||
|
||||
@Autowired
|
||||
private ModuleService moduleService;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
if (alreadySetup) {
|
||||
log.info("SetupModuleBookshelf already executed, skipping");
|
||||
return;
|
||||
}
|
||||
if (!moduleService.importData(BookshelfConstants.BOOKSHELF)) {
|
||||
log.info("Module Bookshelf should not setup data");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("Set up Bookshelf data");
|
||||
Author douglasadams = createAuthorIfNotFound("Douglas", "Adams");
|
||||
moduleService.setDataImported(BookshelfConstants.BOOKSHELF);
|
||||
}
|
||||
|
||||
private Author createAuthorIfNotFound(String firstName, String lastName) {
|
||||
log.info("createAuthorIfNotFound {} {}", firstName, lastName);
|
||||
Author author = authorRepository.findByFirstNameAndLastName(firstName, lastName);
|
||||
if (author == null) {
|
||||
log.info("Author {} {} not found, will create it", firstName, lastName);
|
||||
author = new Author();
|
||||
author.setFirstName(firstName);
|
||||
author.setLastName(lastName);
|
||||
authorRepository.save(author);
|
||||
}
|
||||
return author;
|
||||
}
|
||||
|
||||
private BookshelfPublisher createPublisherIfNotFound(String publisherName) {
|
||||
log.info("createPublisherIfNotFound {}", publisherName);
|
||||
BookshelfPublisher publisher = publisherRepository.findByName(publisherName);
|
||||
if (publisher == null) {
|
||||
log.info("Publisher {} not found, will create it", publisherName);
|
||||
publisher = new BookshelfPublisher();
|
||||
publisher.setName(publisherName);
|
||||
publisherRepository.save(publisher);
|
||||
}
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "title"), uniqueConstraints = @UniqueConstraint(columnNames = {"title"}))
|
||||
public class Article extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String title;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "article")
|
||||
@Nullable
|
||||
private List<ArticleAuthor> authors = new LinkedList<>();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "author_id, article_id"), uniqueConstraints = @UniqueConstraint(columnNames = {"author_id", "article_id"}))
|
||||
public class ArticleAuthor extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "author_id")
|
||||
@NotNull
|
||||
private Author author;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "article_id")
|
||||
@NotNull
|
||||
private Article article;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ArticleAuthorRepository extends JpaRepository<ArticleAuthor, String> {
|
||||
|
||||
List<ArticleAuthor> findByAuthor(Author author);
|
||||
|
||||
List<ArticleAuthor> findByArticle(Article article);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface ArticleRepository extends JpaRepository<Article, String> {
|
||||
|
||||
@Query("select a from Article a " +
|
||||
"where lower(a.title) like lower(concat('%', :searchTerm, '%'))")
|
||||
List<Article> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
List<Article> findByTitle(String title);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = {
|
||||
@Index(columnList = "firstName, lastName"),
|
||||
@Index(columnList = "lastName, firstName")
|
||||
}, uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = { "firstName", "lastName" })
|
||||
})
|
||||
public class Author extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String firstName;
|
||||
|
||||
@NotEmpty
|
||||
private String lastName;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "author")
|
||||
@Nullable
|
||||
private List<BookAuthor> bookAuthors = new LinkedList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "author")
|
||||
@Nullable
|
||||
private List<ArticleAuthor> articleAuthors = new LinkedList<>();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface AuthorRepository extends JpaRepository<Author, String> {
|
||||
|
||||
@Query("select a from Author a " +
|
||||
"where lower(a.firstName) like lower(concat('%', :searchTerm, '%')) " +
|
||||
"or lower(a.lastName) like lower(concat('%', :searchTerm, '%'))")
|
||||
List<Author> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
Author findByFirstNameAndLastName(String firstName, String lastName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "title, isbn"), uniqueConstraints = @UniqueConstraint(columnNames = {"isbn"}))
|
||||
public class Book extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String title;
|
||||
|
||||
@NotEmpty
|
||||
private String isbn;
|
||||
|
||||
@Nullable
|
||||
private int year;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "book")
|
||||
@Nullable
|
||||
private List<BookAuthor> authors = new LinkedList<>();
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "publisher_id")
|
||||
@NotNull
|
||||
@JsonIgnoreProperties({ "books" })
|
||||
private BookshelfPublisher publisher;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "author_id, book_id"), uniqueConstraints = @UniqueConstraint(columnNames = {"author_id", "book_id"}))
|
||||
public class BookAuthor extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "author_id")
|
||||
@NotNull
|
||||
private Author author;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "book_id")
|
||||
@NotNull
|
||||
private Book book;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface BookAuthorRepository extends JpaRepository<BookAuthor, String> {
|
||||
|
||||
List<BookAuthor> findByAuthor(Author author);
|
||||
|
||||
List<BookAuthor> findByBook(Book book);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface BookRepository extends JpaRepository<Book, String> {
|
||||
|
||||
@Query("select b from Book b " +
|
||||
"where lower(b.title) like lower(concat('%', :searchTerm, '%')) " +
|
||||
"or lower(b.isbn) like lower(concat('%', :searchTerm, '%'))")
|
||||
List<Book> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
List<Book> findByTitle(String name);
|
||||
|
||||
List<Book> findByTitleIgnoreCase(String name);
|
||||
|
||||
List<Book> findByIsbn(String isbn);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "name"), uniqueConstraints = @UniqueConstraint(columnNames = { "name" }))
|
||||
public class BookshelfPublisher extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "publisher", orphanRemoval = true)
|
||||
@Nullable
|
||||
List<Book> books = new LinkedList<>();
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package de.thpeetz.kontor.bookshelf.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface BookshelfPublisherRepository extends JpaRepository<BookshelfPublisher, String> {
|
||||
|
||||
@Query("select p from BookshelfPublisher p " +
|
||||
"where lower(p.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<BookshelfPublisher> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
BookshelfPublisher findByName(String name);
|
||||
|
||||
List<BookshelfPublisher> findByNameIgnoreCase(String name);
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package de.thpeetz.kontor.bookshelf.services;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.bookshelf.data.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class BookshelfService {
|
||||
|
||||
private final AuthorRepository authorRepository;
|
||||
private final ArticleAuthorRepository articleAuthorRepository;
|
||||
private final ArticleRepository articleRepository;
|
||||
private final BookRepository bookRepository;
|
||||
private final BookAuthorRepository bookAuthorRepository;
|
||||
private final BookshelfPublisherRepository publisherRepository;
|
||||
|
||||
public BookshelfService(AuthorRepository authorRepository, ArticleAuthorRepository articleAuthorRepository,
|
||||
ArticleRepository articleRepository, BookRepository bookRepository,
|
||||
BookAuthorRepository bookAuthorRepository, BookshelfPublisherRepository publisherRepository) {
|
||||
this.authorRepository = authorRepository;
|
||||
this.articleAuthorRepository = articleAuthorRepository;
|
||||
this.articleRepository = articleRepository;
|
||||
this.bookRepository = bookRepository;
|
||||
this.bookAuthorRepository = bookAuthorRepository;
|
||||
this.publisherRepository = publisherRepository;
|
||||
}
|
||||
|
||||
public List<BookshelfPublisher> findAllPublishers(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return publisherRepository.findAll();
|
||||
} else {
|
||||
return publisherRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public BookshelfPublisher findPublisherByName(String publisherName) {
|
||||
return publisherRepository.findByName(publisherName);
|
||||
}
|
||||
|
||||
public void deletePublisher(BookshelfPublisher publisher) {
|
||||
publisherRepository.delete(publisher);
|
||||
}
|
||||
|
||||
public void savePublisher(BookshelfPublisher publisher) {
|
||||
if (publisher == null) {
|
||||
log.warn("Publisher is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
publisherRepository.save(publisher);
|
||||
}
|
||||
|
||||
public List<Author> findAllAuthors(String filter) {
|
||||
if (filter == null || filter.isEmpty()) {
|
||||
return authorRepository.findAll();
|
||||
} else {
|
||||
return authorRepository.search(filter);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAuthor(Author author) {
|
||||
if (author == null) {
|
||||
log.warn("Author is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
authorRepository.save(author);
|
||||
}
|
||||
|
||||
public void deleteAuthor(Author author) {
|
||||
authorRepository.delete(author);
|
||||
}
|
||||
|
||||
public List<Book> findAllBooks(String filter) {
|
||||
if (filter == null || filter.isEmpty()) {
|
||||
return bookRepository.findAll();
|
||||
} else {
|
||||
return bookRepository.search(filter);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveBook(Book book) {
|
||||
if (book == null) {
|
||||
log.warn("Book is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
bookRepository.save(book);
|
||||
}
|
||||
|
||||
public void deleteBook(Book book) {
|
||||
BookshelfPublisher publisher = book.getPublisher();
|
||||
publisher.getBooks().remove(book);
|
||||
publisherRepository.save(publisher);
|
||||
bookRepository.delete(book);
|
||||
}
|
||||
|
||||
public List<Article> findAllArticles(String filter) {
|
||||
if (filter == null || filter.isEmpty()) {
|
||||
return articleRepository.findAll();
|
||||
} else {
|
||||
return articleRepository.search(filter);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveArticle(Article article) {
|
||||
if (article == null) {
|
||||
log.warn("Article is null, Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
articleRepository.save(article);
|
||||
}
|
||||
|
||||
public void deleteArticle(Article article) {
|
||||
articleRepository.delete(article);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
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.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
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.bookshelf.data.Article;
|
||||
import de.thpeetz.kontor.bookshelf.data.Author;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class ArticleForm extends FormLayout {
|
||||
|
||||
TextField title = new TextField("Title");
|
||||
Grid<Author> author = new Grid<>(Author.class);
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Article> binder = new BeanValidationBinder<>(Article.class);
|
||||
|
||||
public ArticleForm() {
|
||||
addClassName("article-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
add(title, author, 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 ArticleForm.DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new ArticleForm.CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new ArticleForm.SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setArticle(Article article) {
|
||||
binder.setBean(article);
|
||||
}
|
||||
|
||||
public abstract static class ArticleFormEvent extends ComponentEvent<ArticleForm> {
|
||||
private Article article;
|
||||
|
||||
protected ArticleFormEvent(ArticleForm source, Article article) {
|
||||
super(source, false);
|
||||
this.article = article;
|
||||
}
|
||||
|
||||
public Article getArticle() {
|
||||
return article;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends ArticleForm.ArticleFormEvent {
|
||||
SaveEvent(ArticleForm source, Article article) {
|
||||
super(source, article);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends ArticleForm.ArticleFormEvent {
|
||||
DeleteEvent(ArticleForm source, Article article) {
|
||||
super(source, article);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends ArticleForm.ArticleFormEvent {
|
||||
CloseEvent(ArticleForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<ArticleForm.DeleteEvent> listener) {
|
||||
addListener(ArticleForm.DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<ArticleForm.SaveEvent> listener) {
|
||||
addListener(ArticleForm.SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<ArticleForm.CloseEvent> listener) {
|
||||
addListener(ArticleForm.CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import de.thpeetz.kontor.bookshelf.BookshelfConstants;
|
||||
import de.thpeetz.kontor.bookshelf.data.Article;
|
||||
import de.thpeetz.kontor.bookshelf.data.Book;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookAuthor;
|
||||
import de.thpeetz.kontor.bookshelf.services.BookshelfService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = BookshelfConstants.ARTICLE_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Article | Bookshelf | Kontor")
|
||||
public class ArticleView extends VerticalLayout {
|
||||
|
||||
@Getter
|
||||
Grid<Article> grid = new Grid<>(Article.class);
|
||||
TextField filterText = new TextField();
|
||||
@Getter
|
||||
ArticleForm form;
|
||||
BookshelfService service;
|
||||
|
||||
public ArticleView(BookshelfService service) {
|
||||
this.service = service;
|
||||
addClassName("article-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("article-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("title");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editArticle(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new ArticleForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveArticle);
|
||||
form.addDeleteListener(this::deleteArticle);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveArticle(ArticleForm.SaveEvent event) {
|
||||
service.saveArticle(event.getArticle());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteArticle(ArticleForm.DeleteEvent event) {
|
||||
service.deleteArticle(event.getArticle());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by title or isbn...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addArticleButton = new Button("Add article");
|
||||
addArticleButton.addClickListener(click -> addArticle());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addArticleButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editArticle(Article article) {
|
||||
if (article == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setArticle(article);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setArticle(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addArticle() {
|
||||
grid.asSingleSelect().clear();
|
||||
editArticle(new Article());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllArticles(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.listbox.ListBox;
|
||||
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.bookshelf.data.Author;
|
||||
import de.thpeetz.kontor.bookshelf.data.Book;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class AuthorForm extends FormLayout {
|
||||
|
||||
TextField firstName = new TextField("First Name");
|
||||
TextField lastName = new TextField("Last Name");
|
||||
ListBox<Book> books = new ListBox<>();
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Author> binder = new BeanValidationBinder<>(Author.class);
|
||||
|
||||
public AuthorForm() {
|
||||
addClassName("author-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
books.setHeight("100px");
|
||||
//books.setColumns("title", "publisher.name");
|
||||
//books.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
add(firstName, lastName, books, 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 AuthorForm.DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new AuthorForm.CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new AuthorForm.SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthor(Author author) {
|
||||
binder.setBean(author);
|
||||
}
|
||||
|
||||
public void setBooks(List<Book> books) {
|
||||
log.info("setting Books: ", books);
|
||||
this.books.setItems(books);
|
||||
}
|
||||
|
||||
public abstract static class AuthorFormEvent extends ComponentEvent<AuthorForm> {
|
||||
private Author author;
|
||||
|
||||
protected AuthorFormEvent(AuthorForm source, Author author) {
|
||||
super(source, false);
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends AuthorForm.AuthorFormEvent {
|
||||
SaveEvent(AuthorForm source, Author author) {
|
||||
super(source, author);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends AuthorForm.AuthorFormEvent {
|
||||
DeleteEvent(AuthorForm source, Author author) {
|
||||
super(source, author);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends AuthorForm.AuthorFormEvent {
|
||||
CloseEvent(AuthorForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<AuthorForm.DeleteEvent> listener) {
|
||||
addListener(AuthorForm.DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<AuthorForm.SaveEvent> listener) {
|
||||
addListener(AuthorForm.SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<AuthorForm.CloseEvent> listener) {
|
||||
addListener(AuthorForm.CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.bookshelf.BookshelfConstants;
|
||||
import de.thpeetz.kontor.bookshelf.data.Author;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookAuthor;
|
||||
import de.thpeetz.kontor.bookshelf.services.BookshelfService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = BookshelfConstants.AUTHOR_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Author | Bookshelf | Kontor")
|
||||
public class AuthorView extends VerticalLayout {
|
||||
|
||||
Grid<Author> grid = new Grid<>(Author.class);
|
||||
TextField filterText = new TextField();
|
||||
AuthorForm form;
|
||||
BookshelfService service;
|
||||
|
||||
public AuthorView(BookshelfService service) {
|
||||
this.service = service;
|
||||
addClassName("author-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
public Grid<Author> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public AuthorForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("author-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("firstName", "lastName");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editAuthor(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new AuthorForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveAuthor);
|
||||
form.addDeleteListener(this::deleteAuthor);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
private void saveAuthor(AuthorForm.SaveEvent event) {
|
||||
service.saveAuthor(event.getAuthor());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteAuthor(AuthorForm.DeleteEvent event) {
|
||||
service.deleteAuthor(event.getAuthor());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addAuthorButton = new Button("Add author");
|
||||
addAuthorButton.addClickListener(click -> addAuthor());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addAuthorButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editAuthor(Author author) {
|
||||
if (author == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setAuthor(author);
|
||||
form.setBooks(author.getBookAuthors().stream().map(BookAuthor::getBook).collect(Collectors.toList()));
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setAuthor(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addAuthor() {
|
||||
grid.asSingleSelect().clear();
|
||||
editAuthor(new Author());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllAuthors(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.textfield.IntegerField;
|
||||
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.bookshelf.data.Book;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookshelfPublisher;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class BookForm extends FormLayout {
|
||||
|
||||
TextField title = new TextField("Title");
|
||||
TextField isbn = new TextField("ISBN");
|
||||
IntegerField year = new IntegerField("Year");
|
||||
ComboBox<BookshelfPublisher> publisher = new ComboBox<>("Publisher");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Book> binder = new BeanValidationBinder<>(Book.class);
|
||||
|
||||
public BookForm(List<BookshelfPublisher> publishers) {
|
||||
addClassName("book-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
publisher.setItems(publishers);
|
||||
publisher.setItemLabelGenerator(BookshelfPublisher::getName);
|
||||
add(title, isbn, year, publisher, 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 BookForm.DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new BookForm.CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new BookForm.SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setBook(Book book) {
|
||||
binder.setBean(book);
|
||||
}
|
||||
|
||||
public abstract static class BookFormEvent extends ComponentEvent<BookForm> {
|
||||
private Book book;
|
||||
|
||||
protected BookFormEvent(BookForm source, Book book) {
|
||||
super(source, false);
|
||||
this.book = book;
|
||||
}
|
||||
|
||||
public Book getBook() {
|
||||
return book;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends BookForm.BookFormEvent {
|
||||
SaveEvent(BookForm source, Book book) {
|
||||
super(source, book);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends BookForm.BookFormEvent {
|
||||
DeleteEvent(BookForm source, Book book) {
|
||||
super(source, book);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends BookForm.BookFormEvent {
|
||||
CloseEvent(BookForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<BookForm.DeleteEvent> listener) {
|
||||
addListener(BookForm.DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<BookForm.SaveEvent> listener) {
|
||||
addListener(BookForm.SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<BookForm.CloseEvent> listener) {
|
||||
addListener(BookForm.CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.bookshelf.BookshelfConstants;
|
||||
import de.thpeetz.kontor.bookshelf.data.Book;
|
||||
import de.thpeetz.kontor.bookshelf.services.BookshelfService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.Getter;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = BookshelfConstants.BOOK_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Book | Bookshelf | Kontor")
|
||||
public class BookView extends VerticalLayout {
|
||||
|
||||
@Getter
|
||||
Grid<Book> grid = new Grid<>(Book.class);
|
||||
TextField filterText = new TextField();
|
||||
@Getter
|
||||
BookForm form;
|
||||
BookshelfService service;
|
||||
|
||||
public BookView(BookshelfService service) {
|
||||
this.service = service;
|
||||
addClassName("book-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("book-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("title", "isbn", "publisher.name", "year");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editBook(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new BookForm(service.findAllPublishers(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveBook);
|
||||
form.addDeleteListener(this::deleteBook);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveBook(BookForm.SaveEvent event) {
|
||||
service.saveBook(event.getBook());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteBook(BookForm.DeleteEvent event) {
|
||||
service.deleteBook(event.getBook());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by title or isbn...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addBookButton = new Button("Add book");
|
||||
addBookButton.addClickListener(click -> addBook());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addBookButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editBook(Book book) {
|
||||
if (book == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setBook(book);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setBook(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addBook() {
|
||||
grid.asSingleSelect().clear();
|
||||
editBook(new Book());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllBooks(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.bookshelf.BookshelfConstants;
|
||||
import de.thpeetz.kontor.common.views.KontorLayoutUtil;
|
||||
import de.thpeetz.kontor.security.SecurityService;
|
||||
|
||||
public class BookshelfLayout extends AppLayout {
|
||||
|
||||
private final AdminService adminService;
|
||||
|
||||
private final SecurityService securityService;
|
||||
|
||||
public BookshelfLayout(AdminService adminService, SecurityService securityService) {
|
||||
this.adminService = adminService;
|
||||
this.securityService = securityService;
|
||||
|
||||
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService);
|
||||
layout.setSecondaryNavigation(getSecondaryNavigation());
|
||||
layout.createHeader(BookshelfConstants.BOOKSHELF);
|
||||
}
|
||||
|
||||
private HorizontalLayout getSecondaryNavigation() {
|
||||
HorizontalLayout navigation = new HorizontalLayout();
|
||||
navigation.addClassNames(LumoUtility.JustifyContent.CENTER, LumoUtility.Gap.SMALL, LumoUtility.Height.MEDIUM);
|
||||
navigation.add(BookshelfConstants.getBookLink(), BookshelfConstants.getArticleLink(),
|
||||
BookshelfConstants.getPublisherLink(), BookshelfConstants.getAuthorLink());
|
||||
return navigation;
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import de.thpeetz.kontor.common.views.SeparateMainLayout;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.bookshelf.BookshelfConstants;
|
||||
import de.thpeetz.kontor.bookshelf.data.BookshelfPublisher;
|
||||
import de.thpeetz.kontor.bookshelf.services.BookshelfService;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = BookshelfConstants.PUBLISHER_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Publisher | Bookshelf | Kontor")
|
||||
public class BookshelfPublisherView extends VerticalLayout {
|
||||
|
||||
Grid<BookshelfPublisher> grid = new Grid<>(BookshelfPublisher.class);
|
||||
TextField filterText = new TextField();
|
||||
PublisherForm form;
|
||||
|
||||
BookshelfService service;
|
||||
|
||||
public BookshelfPublisherView(BookshelfService service) {
|
||||
this.service = service;
|
||||
addClassName("publisher-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("publisher-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editPublisher(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new PublisherForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::savePublisher);
|
||||
form.addDeleteListener(this::deletePublisher);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void savePublisher(PublisherForm.SaveEvent event) {
|
||||
service.savePublisher(event.getPublisher());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deletePublisher(PublisherForm.DeleteEvent event) {
|
||||
service.deletePublisher(event.getPublisher());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
public Grid<BookshelfPublisher> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public PublisherForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addPublisherButton = new Button("Add publisher");
|
||||
addPublisherButton.addClickListener(click -> addPublisher());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addPublisherButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editPublisher(BookshelfPublisher publisher) {
|
||||
if (publisher == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setPublisher(publisher);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setPublisher(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addPublisher() {
|
||||
grid.asSingleSelect().clear();
|
||||
editPublisher(new BookshelfPublisher());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllPublishers(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package de.thpeetz.kontor.bookshelf.views;
|
||||
|
||||
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.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.bookshelf.data.BookshelfPublisher;
|
||||
|
||||
public class PublisherForm extends FormLayout {
|
||||
private TextField name = new TextField("Name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<BookshelfPublisher> binder = new BeanValidationBinder(BookshelfPublisher.class);
|
||||
|
||||
public PublisherForm() {
|
||||
addClassName("publisher-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
add(name, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public TextField getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(TextField name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setPublisher(BookshelfPublisher publisher) {
|
||||
binder.setBean(publisher);
|
||||
}
|
||||
|
||||
public abstract static class PublisherFormEvent extends ComponentEvent<PublisherForm> {
|
||||
private BookshelfPublisher publisher;
|
||||
|
||||
protected PublisherFormEvent(PublisherForm source, BookshelfPublisher publisher) {
|
||||
super(source, false);
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
public BookshelfPublisher getPublisher() {
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends PublisherFormEvent {
|
||||
SaveEvent(PublisherForm source, BookshelfPublisher publisher) {
|
||||
super(source, publisher);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends PublisherFormEvent {
|
||||
DeleteEvent(PublisherForm source, BookshelfPublisher publisher) {
|
||||
super(source, publisher);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends PublisherFormEvent {
|
||||
CloseEvent(PublisherForm 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,93 @@
|
||||
package de.thpeetz.kontor.comics;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.sidenav.SideNavItem;
|
||||
import com.vaadin.flow.router.RouterLink;
|
||||
|
||||
import de.thpeetz.kontor.comics.views.ArtistView;
|
||||
import de.thpeetz.kontor.comics.views.ComicView;
|
||||
import de.thpeetz.kontor.comics.views.ComicWorkView;
|
||||
import de.thpeetz.kontor.comics.views.IssueView;
|
||||
import de.thpeetz.kontor.comics.views.PublisherView;
|
||||
import de.thpeetz.kontor.comics.views.StoryArcView;
|
||||
import de.thpeetz.kontor.comics.views.TradePaperbackView;
|
||||
import de.thpeetz.kontor.comics.views.VolumeView;
|
||||
import de.thpeetz.kontor.comics.views.WorktypeView;
|
||||
|
||||
/**
|
||||
* The {@code ComicConstants} class contains constant values related to comics.
|
||||
*/
|
||||
public class ComicConstants {
|
||||
|
||||
public static final String COMICS = "Comics";
|
||||
public static final String COMICS_ROUTE = "comics/comic";
|
||||
public static final String PUBLISHER = "Publisher";
|
||||
public static final String PUBLISHER_ROUTE = "comics/publisher";
|
||||
public static final String COMICWORK = "ComicWork";
|
||||
public static final String COMICWORK_ROUTE = "comics/comicwork";
|
||||
public static final String WORKTYPE = "Worktype";
|
||||
public static final String WORKTYPE_ROUTE = "comics/worktype";
|
||||
public static final String ARTIST = "Artist";
|
||||
public static final String ARTIST_ROUTE = "comics/artist";
|
||||
public static final String TPB = "TradePaperback";
|
||||
public static final String TPB_ROUTE = "comics/tradepaperback";
|
||||
public static final String STORYARC = "Story Arc";
|
||||
public static final String STORYARC_ROTE = "comics/storyarc";
|
||||
public static final String ISSUE = "Issue";
|
||||
public static final String ISSUE_ROUTE = "comics/issue";
|
||||
public static final String VOLUME = "Volume";
|
||||
public static final String VOLUME_ROUTE = "comics/volume";
|
||||
|
||||
public static RouterLink getArtistLink() {
|
||||
return new RouterLink(ARTIST, ArtistView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getComicLink() {
|
||||
return new RouterLink(COMICS, ComicView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getPublisherLink() {
|
||||
return new RouterLink(PUBLISHER, PublisherView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getComicWorkLink() {
|
||||
return new RouterLink(COMICWORK, ComicWorkView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getIssueLink() {
|
||||
return new RouterLink(ISSUE, IssueView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getTradePaperbackLink() {
|
||||
return new RouterLink(TPB, TradePaperbackView.class);
|
||||
}
|
||||
|
||||
public static Component getStoryArcLink() {
|
||||
return new RouterLink(STORYARC, StoryArcView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getWorktypeLink() {
|
||||
return new RouterLink(WORKTYPE, WorktypeView.class);
|
||||
}
|
||||
|
||||
public static RouterLink getVolumeLink() {
|
||||
return new RouterLink(VOLUME, VolumeView.class);
|
||||
}
|
||||
|
||||
public static SideNavItem getComicsNavigation() {
|
||||
SideNavItem comics = new SideNavItem(COMICS, COMICS_ROUTE, VaadinIcon.RECORDS.create());
|
||||
comics.addItem(new SideNavItem(ARTIST, ArtistView.class));
|
||||
comics.addItem(new SideNavItem(COMICS, ComicView.class));
|
||||
comics.addItem(new SideNavItem(PUBLISHER, PublisherView.class));
|
||||
comics.addItem(new SideNavItem(ISSUE, IssueView.class));
|
||||
comics.addItem(new SideNavItem(TPB, TradePaperbackView.class));
|
||||
comics.addItem(new SideNavItem(STORYARC, StoryArcView.class));
|
||||
comics.addItem(new SideNavItem(VOLUME, VolumeView.class));
|
||||
return comics;
|
||||
}
|
||||
|
||||
private ComicConstants() {
|
||||
// private constructor to hide the implicit public one
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Represents an artist in the system.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Slf4j
|
||||
@Entity
|
||||
public class Artist extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
@Column(unique = true)
|
||||
private String name;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "artist", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
List<ComicWork> comicWorks = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("Artist{");
|
||||
sb.append("name='").append(name).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface ArtistRepository extends JpaRepository<Artist, String> {
|
||||
@Query("select a from Artist a " +
|
||||
"where lower(a.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Artist> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
List<Artist> findByNameIgnoreCase(String name);
|
||||
|
||||
Artist findByName(String name);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Represents a comic entity.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class Comic extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
@Column(unique = true)
|
||||
private String title;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "publisher_id")
|
||||
@NotNull
|
||||
@JsonIgnoreProperties({ "comics" })
|
||||
private Publisher publisher;
|
||||
|
||||
private Boolean currentOrder = false;
|
||||
|
||||
private Boolean completed = false;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "comic", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
List<ComicWork> comicWorks;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "comic", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
private List<Issue> issues = new LinkedList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "comic", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
private List<StoryArc> storyArcs = new LinkedList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "comic", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
private List<TradePaperback> tradePaperbacks = new LinkedList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "comic", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
private List<Volume> volumes = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("Comic{");
|
||||
sb.append("title='").append(title).append('\'');
|
||||
sb.append(", publisher=").append(publisher);
|
||||
sb.append(", currentOrder=").append(currentOrder);
|
||||
sb.append(", completed=").append(completed);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getPublisherName() {
|
||||
return this.publisher.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface ComicRepository extends JpaRepository<Comic, String> {
|
||||
@Query("select c from Comic c " +
|
||||
"where lower(c.title) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Comic> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
Comic findByTitleAndPublisher(String title, Publisher publisher);
|
||||
|
||||
List<Comic> findByTitle(String title);
|
||||
|
||||
List<Comic> findByTitleIgnoreCase(String title);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
@Table(indexes = {@Index(columnList = "comic_id, artist_id, workType_id") },
|
||||
uniqueConstraints = @UniqueConstraint(columnNames = {"comic_id", "artist_id", "workType_id" })
|
||||
)
|
||||
public class ComicWork extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "comic_id")
|
||||
@NotNull
|
||||
private Comic comic;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "artist_id")
|
||||
@NotNull
|
||||
private Artist artist;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "workType_id")
|
||||
@NotNull
|
||||
private Worktype workType;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("ComicWork{");
|
||||
sb.append("comic=").append(comic);
|
||||
sb.append(", artist=").append(artist);
|
||||
sb.append(", workType=").append(workType);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
public interface ComicWorkRepository extends JpaRepository<ComicWork, String> {
|
||||
|
||||
@Query("SELECT c from ComicWork c where c.comic = ?1 and c.artist = ?2 and c.workType = ?3")
|
||||
ComicWork findbyComicAndArtistAndWorktype(Comic comic, Artist artist, Worktype worktype);
|
||||
|
||||
@Query("select c from ComicWork c where c.comic = ?1")
|
||||
List<ComicWork> findByComic(Comic comic);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class Issue extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "comic_id")
|
||||
@NotNull
|
||||
@JsonIgnoreProperties({ "issues" })
|
||||
private Comic comic;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "volume_id")
|
||||
@JsonIgnoreProperties({ "issues" })
|
||||
@Nullable
|
||||
private Volume volume;
|
||||
|
||||
@NotEmpty
|
||||
private String issueNumber;
|
||||
|
||||
private Boolean isRead;
|
||||
|
||||
private Boolean inStock;
|
||||
|
||||
public String getComicTitle() {
|
||||
return comic.getTitle();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface IssueRepository extends JpaRepository<Issue, String> {
|
||||
@Query("select i from Issue i " +
|
||||
"where lower(i.issueNumber) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Issue> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
List<Issue> findByComic(Comic comic);
|
||||
|
||||
Issue findByComicAndIssueNumber(Comic comic, String issueNumber);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class Publisher extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
@Column(unique = true)
|
||||
private String name;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "publisher", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@Nullable
|
||||
private List<Comic> comics = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("Publisher{");
|
||||
sb.append("name='").append(name).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface PublisherRepository extends JpaRepository<Publisher, String> {
|
||||
@Query("select p from Publisher p " +
|
||||
"where lower(p.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Publisher> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
Publisher findByName(String name);
|
||||
|
||||
List<Publisher> findByNameIgnoreCase(String name);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class StoryArc extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "comic_id")
|
||||
@NotNull
|
||||
@JsonIgnoreProperties({ "storyArcs" })
|
||||
private Comic comic;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface StoryArcRepository extends JpaRepository<StoryArc, String> {
|
||||
@Query("select s from StoryArc s " +
|
||||
"where lower(s.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<StoryArc> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
StoryArc findByNameAndComic(String name, Comic comic);
|
||||
|
||||
List<StoryArc> findByComic(Comic comic);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class TradePaperback extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "comic_id")
|
||||
@NotNull
|
||||
private Comic comic;
|
||||
|
||||
private Integer issueStart;
|
||||
|
||||
private Integer issueEnd;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface TradePaperbackRepository extends JpaRepository<TradePaperback, String> {
|
||||
@Query("select t from TradePaperback t " +
|
||||
"where lower(t.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<TradePaperback> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
List<TradePaperback> findByComic(Comic comic);
|
||||
|
||||
List<TradePaperback> findByNameAndComic(String name, Comic comic);
|
||||
|
||||
@Query("select t from TradePaperback t where t.name = ?1 and t.comic = ?2 and t.issueStart = ?3 and t.issueEnd = ?4")
|
||||
TradePaperback findByFields(String name, Comic comic, int start, int end);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class Volume extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "comic_id")
|
||||
@NotNull
|
||||
@JsonIgnoreProperties({ "volumes" })
|
||||
private Comic comic;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "volume", cascade = CascadeType.REMOVE, orphanRemoval = true)
|
||||
@Nullable
|
||||
private List<Issue> issues = new LinkedList<>();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface VolumeRepository extends JpaRepository<Volume, String> {
|
||||
|
||||
List<Volume> findByName(String name);
|
||||
|
||||
List<Volume> findByComic(Comic comic);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Represents a work type in the application.
|
||||
* This class extends the AbstractEntity class.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Entity
|
||||
public class Worktype extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
@Column(unique = true)
|
||||
private String name;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "workType", cascade = CascadeType.REFRESH, orphanRemoval = true)
|
||||
@Nullable
|
||||
List<ComicWork> comicWorks = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("Worktype{");
|
||||
sb.append("name='").append(name).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.thpeetz.kontor.comics.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface WorktypeRepository extends JpaRepository<Worktype, String> {
|
||||
@Query("select w from Worktype w " +
|
||||
"where lower(w.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Worktype> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
|
||||
Worktype findByName(String name);
|
||||
|
||||
List<Worktype> findByNameIgnoreCase(String name);
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
package de.thpeetz.kontor.comics.services;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import de.thpeetz.kontor.comics.data.Artist;
|
||||
import de.thpeetz.kontor.comics.data.ArtistRepository;
|
||||
import de.thpeetz.kontor.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.ComicRepository;
|
||||
import de.thpeetz.kontor.comics.data.ComicWork;
|
||||
import de.thpeetz.kontor.comics.data.ComicWorkRepository;
|
||||
import de.thpeetz.kontor.comics.data.Issue;
|
||||
import de.thpeetz.kontor.comics.data.IssueRepository;
|
||||
import de.thpeetz.kontor.comics.data.Publisher;
|
||||
import de.thpeetz.kontor.comics.data.PublisherRepository;
|
||||
import de.thpeetz.kontor.comics.data.StoryArc;
|
||||
import de.thpeetz.kontor.comics.data.StoryArcRepository;
|
||||
import de.thpeetz.kontor.comics.data.TradePaperback;
|
||||
import de.thpeetz.kontor.comics.data.TradePaperbackRepository;
|
||||
import de.thpeetz.kontor.comics.data.Volume;
|
||||
import de.thpeetz.kontor.comics.data.VolumeRepository;
|
||||
import de.thpeetz.kontor.comics.data.Worktype;
|
||||
import de.thpeetz.kontor.comics.data.WorktypeRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ComicService {
|
||||
|
||||
private final PublisherRepository publisherRepository;
|
||||
private final ComicRepository comicRepository;
|
||||
private final ArtistRepository artistRepository;
|
||||
private final IssueRepository issueRepository;
|
||||
private final StoryArcRepository storyArcRepository;
|
||||
private final TradePaperbackRepository tradePaperbackRepository;
|
||||
private final ComicWorkRepository comicWorkRepository;
|
||||
private final VolumeRepository volumeRepository;
|
||||
private final WorktypeRepository worktypeRepository;
|
||||
|
||||
public ComicService(PublisherRepository publisherRepository, ComicRepository comicRepository,
|
||||
ArtistRepository artistRepository, IssueRepository issueRepository, StoryArcRepository storyArcRepository,
|
||||
TradePaperbackRepository tradePaperbackRepository, ComicWorkRepository comicWorkRepository,
|
||||
VolumeRepository volumeRepository, WorktypeRepository worktypeRepository) {
|
||||
|
||||
this.publisherRepository = publisherRepository;
|
||||
this.comicRepository = comicRepository;
|
||||
this.artistRepository = artistRepository;
|
||||
this.issueRepository = issueRepository;
|
||||
this.storyArcRepository = storyArcRepository;
|
||||
this.tradePaperbackRepository = tradePaperbackRepository;
|
||||
this.comicWorkRepository = comicWorkRepository;
|
||||
this.volumeRepository = volumeRepository;
|
||||
this.worktypeRepository = worktypeRepository;
|
||||
}
|
||||
|
||||
public List<Publisher> findAllPublishers(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return publisherRepository.findAll();
|
||||
} else {
|
||||
return publisherRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public Publisher findPublisherByName(String publisherName) {
|
||||
return publisherRepository.findByName(publisherName);
|
||||
}
|
||||
|
||||
public void deletePublisher(Publisher publisher) {
|
||||
publisherRepository.delete(publisher);
|
||||
}
|
||||
|
||||
public void savePublisher(Publisher publisher) {
|
||||
if (publisher == null) {
|
||||
log.warn("Publisher is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
publisherRepository.save(publisher);
|
||||
}
|
||||
|
||||
public List<Comic> findAllComics(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return comicRepository.findAll();
|
||||
} else {
|
||||
return comicRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public Comic findComicByTitle(String title) {
|
||||
List<Comic> comics = comicRepository.findByTitle(title);
|
||||
if (comics.size() == 1) {
|
||||
return comics.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteComic(Comic comic) {
|
||||
Publisher publisher = comic.getPublisher();
|
||||
publisher.getComics().remove(comic);
|
||||
publisherRepository.save(publisher);
|
||||
comicRepository.delete(comic);
|
||||
}
|
||||
|
||||
public void saveComic(Comic comic) {
|
||||
if (comic == null) {
|
||||
log.warn("Comic is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
comicRepository.save(comic);
|
||||
}
|
||||
|
||||
public List<Artist> findAllArtists(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return artistRepository.findAll();
|
||||
} else {
|
||||
return artistRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public Artist findArtistByName(String artistName) {
|
||||
if (artistName == null || artistName.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return artistRepository.findByName(artistName);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteArtist(Artist artist) {
|
||||
artistRepository.delete(artist);
|
||||
}
|
||||
|
||||
public void saveArtist(Artist artist) {
|
||||
if (artist == null) {
|
||||
log.warn("Artist is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
artistRepository.save(artist);
|
||||
}
|
||||
|
||||
public List<Issue> findAllIssues() {
|
||||
return issueRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Issue> findAllIssuesForComic(Comic comic) {
|
||||
if (comic == null) {
|
||||
return issueRepository.findAll();
|
||||
} else {
|
||||
log.info("Find issues for Comic: {}", comic);
|
||||
return issueRepository.findByComic(comic);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveIssue(Issue issue) {
|
||||
if (issue == null) {
|
||||
log.warn("Issue is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
issueRepository.save(issue);
|
||||
}
|
||||
|
||||
public void deleteIssue(Issue issue) {
|
||||
issueRepository.delete(issue);
|
||||
}
|
||||
|
||||
public List<StoryArc> findAllStoryArcs() {
|
||||
return storyArcRepository.findAll();
|
||||
}
|
||||
|
||||
public List<StoryArc> findAllStoryArcsForComic(Comic comic) {
|
||||
if (comic == null) {
|
||||
return storyArcRepository.findAll();
|
||||
} else {
|
||||
log.info("Find Story Arc for Comic: {}", comic);
|
||||
return storyArcRepository.findByComic(comic);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveStoryArc(StoryArc storyArc) {
|
||||
storyArcRepository.save(storyArc);
|
||||
}
|
||||
|
||||
public void deleteStoryArc(StoryArc storyArc) {
|
||||
Comic comic = storyArc.getComic();
|
||||
comic.getStoryArcs().remove(storyArc);
|
||||
comicRepository.save(comic);
|
||||
storyArcRepository.delete(storyArc);
|
||||
}
|
||||
|
||||
public List<TradePaperback> findAllTradePaperbacks(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return tradePaperbackRepository.findAll();
|
||||
} else {
|
||||
return tradePaperbackRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteTradePaperBack(TradePaperback tradepaperback) {
|
||||
tradePaperbackRepository.delete(tradepaperback);
|
||||
}
|
||||
|
||||
public void saveTradePaperBack(TradePaperback tradepaperback) {
|
||||
if (tradepaperback == null) {
|
||||
log.warn("TradePaperBack is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
tradePaperbackRepository.save(tradepaperback);
|
||||
}
|
||||
|
||||
public List<ComicWork> findAllComicWorks() {
|
||||
return comicWorkRepository.findAll();
|
||||
}
|
||||
|
||||
public void saveComicWork(ComicWork comicWork) {
|
||||
if (comicWork == null) {
|
||||
log.warn("ComicWork is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
comicWorkRepository.save(comicWork);
|
||||
}
|
||||
|
||||
public void deleteComicWork(ComicWork comicWork) {
|
||||
Comic comic = comicWork.getComic();
|
||||
comic.getComicWorks().remove(comicWork);
|
||||
comicRepository.save(comic);
|
||||
Artist artist = comicWork.getArtist();
|
||||
artist.getComicWorks().remove(comicWork);
|
||||
artistRepository.save(artist);
|
||||
Worktype worktype = comicWork.getWorkType();
|
||||
worktype.getComicWorks().remove(comicWork);
|
||||
worktypeRepository.save(worktype);
|
||||
comicWorkRepository.delete(comicWork);
|
||||
}
|
||||
|
||||
public List<Volume> findAllVolumes() {
|
||||
return volumeRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Volume> findAllVolumesForComic(Comic comic) {
|
||||
if (comic == null) {
|
||||
return volumeRepository.findAll();
|
||||
} else {
|
||||
log.info("Find Volume for Comic: {}", comic);
|
||||
return volumeRepository.findByComic(comic);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveVolume(Volume volume) {
|
||||
if (volume == null) {
|
||||
log.warn("Volume is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
volumeRepository.save(volume);
|
||||
}
|
||||
|
||||
public void deleteVolume(Volume volume) {
|
||||
Comic comic = volume.getComic();
|
||||
comic.getVolumes().remove(volume);
|
||||
comicRepository.save(comic);
|
||||
volumeRepository.delete(volume);
|
||||
}
|
||||
|
||||
public List<Worktype> findAllWorktypes(String stringFilter) {
|
||||
if (stringFilter == null || stringFilter.isEmpty()) {
|
||||
return worktypeRepository.findAll();
|
||||
} else {
|
||||
return worktypeRepository.search(stringFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public Worktype findWorktypeByName(String worktypeName) {
|
||||
if (worktypeName == null || worktypeName.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return worktypeRepository.findByName(worktypeName);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveWorktype(Worktype worktype) {
|
||||
if (worktype == null) {
|
||||
log.warn("Worktype is null. Are you sure you have connected your form to the application?");
|
||||
return;
|
||||
}
|
||||
worktypeRepository.save(worktype);
|
||||
}
|
||||
|
||||
public void deleteWorktype(Worktype worktype) {
|
||||
List<ComicWork> comicWorks = worktype.getComicWorks();
|
||||
if (comicWorks == null) {
|
||||
log.warn("reference to ComicWork is null");
|
||||
return;
|
||||
}
|
||||
log.info("found {} references to ComicWork", comicWorks.size());
|
||||
comicWorks.forEach(comicWork -> {
|
||||
comicWork.setWorkType(null);
|
||||
});
|
||||
log.info("delete Worktype: {}", worktype);
|
||||
worktypeRepository.delete(worktype);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
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.comics.data.Artist;
|
||||
import de.thpeetz.kontor.comics.data.ComicWork;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class ArtistForm extends FormLayout {
|
||||
|
||||
TextField name = new TextField("Name");
|
||||
Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class);
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Artist> binder = new BeanValidationBinder<>(Artist.class);
|
||||
|
||||
public ArtistForm() {
|
||||
addClassName("artist-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comicWorks.setColumns("workType.name", "comic.title");
|
||||
comicWorks.getColumnByKey("workType.name").setHeader("Work type");
|
||||
comicWorks.getColumnByKey("comic.title").setHeader("Comic");
|
||||
comicWorks.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
add(name, comicWorks, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setArtist(Artist artist) {
|
||||
binder.setBean(artist);
|
||||
}
|
||||
|
||||
public void setComicWorks(List<ComicWork> works) {
|
||||
log.info("Setting comic works: {}", works);
|
||||
this.comicWorks.setItems(works);
|
||||
}
|
||||
|
||||
public abstract static class ArtistFormEvent extends ComponentEvent<ArtistForm> {
|
||||
private Artist artist;
|
||||
|
||||
protected ArtistFormEvent(ArtistForm source, Artist artist) {
|
||||
super(source, false);
|
||||
this.artist = artist;
|
||||
}
|
||||
|
||||
public Artist getArtist() {
|
||||
return artist;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends ArtistFormEvent {
|
||||
SaveEvent(ArtistForm source, Artist artist) {
|
||||
super(source, artist);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends ArtistFormEvent {
|
||||
DeleteEvent(ArtistForm source, Artist artist) {
|
||||
super(source, artist);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends ArtistFormEvent {
|
||||
CloseEvent(ArtistForm 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,124 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.comics.data.Artist;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = "artist", layout = MainLayout.class)
|
||||
@PageTitle("Artist | Comics | Kontor")
|
||||
public class ArtistView extends VerticalLayout {
|
||||
|
||||
@Getter
|
||||
Grid<Artist> grid = new Grid<>(Artist.class);
|
||||
TextField filterText = new TextField();
|
||||
@Getter
|
||||
ArtistForm form;
|
||||
ComicService service;
|
||||
|
||||
public ArtistView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("artist-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("artist-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editArtist(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new ArtistForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveArtist);
|
||||
form.addDeleteListener(this::deleteArtist);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveArtist(ArtistForm.SaveEvent event) {
|
||||
service.saveArtist(event.getArtist());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteArtist(ArtistForm.DeleteEvent event) {
|
||||
service.deleteArtist(event.getArtist());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addArtistButton = new Button("Add artist");
|
||||
addArtistButton.addClickListener(click -> addArtist());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addArtistButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editArtist(Artist artist) {
|
||||
if (artist == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setArtist(artist);
|
||||
form.setComicWorks(artist.getComicWorks());
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setArtist(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addArtist() {
|
||||
grid.asSingleSelect().clear();
|
||||
editArtist(new Artist());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllArtists(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
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.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.ComicWork;
|
||||
import de.thpeetz.kontor.comics.data.Publisher;
|
||||
|
||||
public class ComicForm extends FormLayout {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ComicForm.class);
|
||||
|
||||
TextField title = new TextField("Title");
|
||||
ComboBox<Publisher> publisher = new ComboBox<>("Publisher");
|
||||
Checkbox currentOrder = new Checkbox("Current order");
|
||||
Checkbox completed = new Checkbox("Completed");
|
||||
Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class);
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Comic> binder = new BeanValidationBinder<>(Comic.class);
|
||||
|
||||
public ComicForm(List<Publisher> publishers) {
|
||||
addClassName("comic-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
publisher.setItems(publishers);
|
||||
publisher.setItemLabelGenerator(Publisher::getName);
|
||||
// comicWorks.addClassName("comic-works-grid");
|
||||
// comicWorks.setSizeFull();
|
||||
comicWorks.setColumns("workType.name", "artist.name");
|
||||
comicWorks.getColumnByKey("workType.name").setHeader("Work type");
|
||||
comicWorks.getColumnByKey("artist.name").setHeader("Artist");
|
||||
comicWorks.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
add(title, publisher, currentOrder, completed, comicWorks, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setComic(Comic comic) {
|
||||
binder.setBean(comic);
|
||||
}
|
||||
|
||||
public void setComicWorks(List<ComicWork> works) {
|
||||
log.info("Setting comic works: {}", works);
|
||||
comicWorks.setItems(works);
|
||||
}
|
||||
|
||||
public abstract static class ComicFormEvent extends ComponentEvent<ComicForm> {
|
||||
private Comic comic;
|
||||
|
||||
protected ComicFormEvent(ComicForm source, Comic comic) {
|
||||
super(source, false);
|
||||
this.comic = comic;
|
||||
}
|
||||
|
||||
public Comic getComic() {
|
||||
return comic;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends ComicFormEvent {
|
||||
SaveEvent(ComicForm source, Comic comic) {
|
||||
super(source, comic);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends ComicFormEvent {
|
||||
DeleteEvent(ComicForm source, Comic comic) {
|
||||
super(source, comic);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends ComicFormEvent {
|
||||
CloseEvent(ComicForm 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,43 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.theme.lumo.LumoUtility;
|
||||
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.common.views.KontorLayoutUtil;
|
||||
import de.thpeetz.kontor.security.SecurityService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Represents a custom layout for the comic view in the application.
|
||||
* This layout extends the AppLayout class.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ComicLayout extends AppLayout {
|
||||
|
||||
private final AdminService adminService;
|
||||
|
||||
private final SecurityService securityService;
|
||||
|
||||
public ComicLayout(AdminService adminService, SecurityService securityService) {
|
||||
this.adminService = adminService;
|
||||
this.securityService = securityService;
|
||||
|
||||
KontorLayoutUtil layout = new KontorLayoutUtil(this, adminService, securityService);
|
||||
layout.setSecondaryNavigation(getSecondaryNavigation());
|
||||
layout.createHeader(ComicConstants.COMICS);
|
||||
}
|
||||
|
||||
private HorizontalLayout getSecondaryNavigation() {
|
||||
HorizontalLayout navigation = new HorizontalLayout();
|
||||
navigation.addClassNames(LumoUtility.JustifyContent.CENTER, LumoUtility.Gap.SMALL, LumoUtility.Height.MEDIUM);
|
||||
navigation.add(ComicConstants.getComicLink(), ComicConstants.getPublisherLink(), ComicConstants.getIssueLink(),
|
||||
ComicConstants.getTradePaperbackLink(), ComicConstants.getStoryArcLink(),
|
||||
ComicConstants.getVolumeLink(), ComicConstants.getArtistLink(), ComicConstants.getComicWorkLink(),
|
||||
ComicConstants.getWorktypeLink());
|
||||
return navigation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
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.icon.Icon;
|
||||
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.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.ColumnToggleContextMenu;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import de.thpeetz.kontor.common.views.StatusIcon;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.COMICS_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Comic | Comics | Kontor")
|
||||
public class ComicView extends VerticalLayout {
|
||||
|
||||
@Getter
|
||||
Grid<Comic> grid = new Grid<>(Comic.class, false);
|
||||
Grid.Column<Comic> idColumn = grid.addColumn(Comic::getId)
|
||||
.setHeader("ID").setResizable(true).setSortable(true);
|
||||
Grid.Column<Comic> createdColumn = grid.addColumn(Comic::getCreatedDate)
|
||||
.setHeader("Erstellt").setResizable(true).setSortable(true);
|
||||
Grid.Column<Comic> modifiedColumn = grid.addColumn(Comic::getLastModifiedDate)
|
||||
.setHeader("Geändert").setResizable(true).setSortable(true);
|
||||
Grid.Column<Comic> titleColumn = grid.addColumn(Comic::getTitle)
|
||||
.setHeader("Titel").setResizable(true).setSortable(true);
|
||||
Grid.Column<Comic> publisherColumn = grid.addColumn(Comic::getPublisherName)
|
||||
.setHeader("Verlag").setResizable(true).setSortable(true);
|
||||
Grid.Column<Comic> currentOrderColumn = grid.addComponentColumn(comic -> StatusIcon.create(comic.getCurrentOrder()))
|
||||
.setHeader("Bestellung").setWidth("6rem").setSortable(true);
|
||||
Grid.Column<Comic> completedColumn = grid.addComponentColumn(comic -> StatusIcon.create(comic.getCompleted()))
|
||||
.setHeader("Abgeschlossen").setWidth("6rem").setSortable(true);
|
||||
TextField filterText = new TextField();
|
||||
@Getter
|
||||
ComicForm form;
|
||||
ComicService service;
|
||||
|
||||
public ComicView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("comic-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("comic-grid");
|
||||
grid.setSizeFull();
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editComic(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new ComicForm(service.findAllPublishers(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveComic);
|
||||
form.addDeleteListener(this::deleteComic);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveComic(ComicForm.SaveEvent event) {
|
||||
service.saveComic(event.getComic());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteComic(ComicForm.DeleteEvent event) {
|
||||
service.deleteComic(event.getComic());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setPrefixComponent(new Icon(VaadinIcon.SEARCH));
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addComicButton = new Button("Add comic");
|
||||
addComicButton.addClickListener(click -> addComic());
|
||||
|
||||
Button menuButton = new Button("Show/Hide Columns");
|
||||
menuButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
ColumnToggleContextMenu<Comic> columnToggleContextMenu = new ColumnToggleContextMenu<>(menuButton);
|
||||
columnToggleContextMenu.addColumnToggleItem(idColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(createdColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(modifiedColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(titleColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(publisherColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(currentOrderColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(completedColumn);
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addComicButton, menuButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editComic(Comic comic) {
|
||||
if (comic == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setComic(comic);
|
||||
if (comic.getComicWorks() == null) {
|
||||
log.info("No comic works");
|
||||
} else {
|
||||
log.info("Comic works sze: {}", comic.getComicWorks().size());
|
||||
}
|
||||
form.setComicWorks(comic.getComicWorks());
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setComic(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addComic() {
|
||||
grid.asSingleSelect().clear();
|
||||
editComic(new Comic());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllComics(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
import de.thpeetz.kontor.comics.data.Artist;
|
||||
import de.thpeetz.kontor.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.ComicWork;
|
||||
import de.thpeetz.kontor.comics.data.Worktype;
|
||||
|
||||
public class ComicWorkForm extends FormLayout {
|
||||
ComboBox<Comic> comic = new ComboBox<>("Comic");
|
||||
ComboBox<Artist> artist = new ComboBox<>("Artist");
|
||||
ComboBox<Worktype> workType = new ComboBox<>("Worktype");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<ComicWork> binder = new BeanValidationBinder<>(ComicWork.class);
|
||||
|
||||
public ComicWorkForm(List<Comic> comics, List<Artist> artists, List<Worktype> workTypes) {
|
||||
addClassName("comicwork-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comic.setItems(comics);
|
||||
comic.setItemLabelGenerator(Comic::getTitle);
|
||||
artist.setItems(artists);
|
||||
artist.setItemLabelGenerator(Artist::getName);
|
||||
workType.setItems(workTypes);
|
||||
workType.setItemLabelGenerator(Worktype::getName);
|
||||
add(comic, artist, workType, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setComicWork(ComicWork comicWork) {
|
||||
binder.setBean(comicWork);
|
||||
}
|
||||
|
||||
public abstract static class ComicWorkFormEvent extends ComponentEvent<ComicWorkForm> {
|
||||
private ComicWork comicWork;
|
||||
|
||||
protected ComicWorkFormEvent(ComicWorkForm source, ComicWork comicWork) {
|
||||
super(source, false);
|
||||
this.comicWork = comicWork;
|
||||
}
|
||||
|
||||
public ComicWork getComicWork() {
|
||||
return comicWork;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends ComicWorkFormEvent {
|
||||
SaveEvent(ComicWorkForm source, ComicWork comicWork) {
|
||||
super(source, comicWork);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends ComicWorkFormEvent {
|
||||
DeleteEvent(ComicWorkForm source, ComicWork comicWork) {
|
||||
super(source, comicWork);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends ComicWorkFormEvent {
|
||||
CloseEvent(ComicWorkForm 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,122 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.ComicWork;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.COMICWORK_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("ComicWork | Comics | Kontor")
|
||||
public class ComicWorkView extends VerticalLayout {
|
||||
|
||||
Grid<ComicWork> grid = new Grid<>(ComicWork.class);
|
||||
ComicWorkForm form;
|
||||
ComicService service;
|
||||
|
||||
public ComicWorkView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("comicWork-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
public Grid<ComicWork> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("comic-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("comic.title", "artist.name", "workType.name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editComicWork(event.getValue()));
|
||||
}
|
||||
|
||||
public ComicWorkForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new ComicWorkForm(service.findAllComics(null), service.findAllArtists(null),
|
||||
service.findAllWorktypes(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveComicWork);
|
||||
form.addDeleteListener(this::deleteComicWork);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveComicWork(ComicWorkForm.SaveEvent event) {
|
||||
service.saveComicWork(event.getComicWork());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteComicWork(ComicWorkForm.DeleteEvent event) {
|
||||
service.deleteComicWork(event.getComicWork());
|
||||
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() {
|
||||
Button addComicButton = new Button("Add ComicWork");
|
||||
addComicButton.addClickListener(click -> addComicWork());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(addComicButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editComicWork(ComicWork comicWork) {
|
||||
if (comicWork == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setComicWork(comicWork);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setComicWork(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addComicWork() {
|
||||
grid.asSingleSelect().clear();
|
||||
editComicWork(new ComicWork());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllComicWorks());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
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.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.Issue;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class IssueForm extends FormLayout {
|
||||
|
||||
ComboBox<Comic> comic = new ComboBox<>("Comic");
|
||||
TextField issueNumber = new TextField("Issue number");
|
||||
Checkbox isRead = new Checkbox("Read");
|
||||
Checkbox inStock = new Checkbox("In stock");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Issue> binder = new BeanValidationBinder<>(Issue.class);
|
||||
|
||||
public IssueForm(List<Comic> comics) {
|
||||
addClassName("issue-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comic.setItems(comics);
|
||||
comic.setItemLabelGenerator(Comic::getTitle);
|
||||
add(comic, issueNumber, isRead, inStock, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setIssue(Issue issue) {
|
||||
binder.setBean(issue);
|
||||
}
|
||||
|
||||
public abstract static class IssueFormEvent extends ComponentEvent<IssueForm> {
|
||||
private Issue issue;
|
||||
|
||||
protected IssueFormEvent(IssueForm source, Issue issue) {
|
||||
super(source, false);
|
||||
this.issue = issue;
|
||||
}
|
||||
|
||||
public Issue getIssue() {
|
||||
return issue;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends IssueFormEvent {
|
||||
SaveEvent(IssueForm source, Issue issue) {
|
||||
super(source, issue);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends IssueFormEvent {
|
||||
DeleteEvent(IssueForm source, Issue issue) {
|
||||
super(source, issue);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends IssueFormEvent {
|
||||
CloseEvent(IssueForm 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,169 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.grid.GridSortOrder;
|
||||
import com.vaadin.flow.data.provider.SortDirection;
|
||||
import de.thpeetz.kontor.common.views.ColumnToggleContextMenu;
|
||||
import de.thpeetz.kontor.common.views.StatusIcon;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
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.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.Issue;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.ISSUE_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Issue | Comics | Kontor")
|
||||
public class IssueView extends VerticalLayout {
|
||||
|
||||
@Getter
|
||||
Grid<Issue> grid = new Grid<>(Issue.class, false);
|
||||
Grid.Column<Issue> idColumn = grid.addColumn(Issue::getId)
|
||||
.setHeader("ID").setResizable(true).setSortable(true);
|
||||
Grid.Column<Issue> createdColumn = grid.addColumn(Issue::getCreatedDate)
|
||||
.setHeader("Erstellt").setResizable(true).setSortable(true);
|
||||
Grid.Column<Issue> modifiedColumn = grid.addColumn(Issue::getLastModifiedDate)
|
||||
.setHeader("Geändert").setResizable(true).setSortable(true);
|
||||
Grid.Column<Issue> versionColumn = grid.addColumn(Issue::getVersion)
|
||||
.setHeader("Version").setResizable(true).setSortable(true);
|
||||
Grid.Column<Issue> titleColumn = grid.addColumn(Issue::getComicTitle)
|
||||
.setHeader("Comic").setResizable(true).setSortable(true);
|
||||
Grid.Column<Issue> issueNumberColumn = grid.addColumn(Issue::getIssueNumber)
|
||||
.setHeader("Heft Nummer").setResizable(true).setSortable(true);
|
||||
Grid.Column<Issue> isReadColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getIsRead()))
|
||||
.setHeader("Gelesen?").setWidth("6rem").setSortable(true);
|
||||
Grid.Column<Issue> inStockColumn = grid.addComponentColumn(issueColumn -> StatusIcon.create(issueColumn.getInStock()))
|
||||
.setHeader("Im Bestand?").setWidth("6rem").setSortable(true);
|
||||
ComboBox<Comic> comicFilter = new ComboBox<>("Comic");
|
||||
@Getter
|
||||
IssueForm form;
|
||||
ComicService service;
|
||||
|
||||
public IssueView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("issue-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("issue-grid");
|
||||
grid.setSizeFull();
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
idColumn.setVisible(false);
|
||||
createdColumn.setVisible(false);
|
||||
modifiedColumn.setVisible(false);
|
||||
versionColumn.setVisible(false);
|
||||
grid.setMultiSort(true);
|
||||
List<GridSortOrder<Issue>> sortOrder = new ArrayList<>();
|
||||
sortOrder.add(new GridSortOrder<Issue>(titleColumn, SortDirection.ASCENDING));
|
||||
sortOrder.add(new GridSortOrder<Issue>(issueNumberColumn, SortDirection.ASCENDING));
|
||||
grid.sort(sortOrder);
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editIssue(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new IssueForm(service.findAllComics(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveIssue);
|
||||
form.addDeleteListener(this::deleteIssue);
|
||||
form.addCloseListener(e -> 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() {
|
||||
comicFilter.setItems(service.findAllComics(null));
|
||||
comicFilter.setItemLabelGenerator(Comic::getTitle);
|
||||
comicFilter.setClearButtonVisible(true);
|
||||
comicFilter.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addIssueButton = new Button("Add issue");
|
||||
addIssueButton.addClickListener(click -> addIssue());
|
||||
|
||||
Button menuButton = new Button("Show/Hide Columns");
|
||||
menuButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
ColumnToggleContextMenu<Issue> columnToggleContextMenu = new ColumnToggleContextMenu<>(menuButton);
|
||||
columnToggleContextMenu.addColumnToggleItem(idColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(createdColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(modifiedColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(versionColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(titleColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(issueNumberColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(isReadColumn);
|
||||
columnToggleContextMenu.addColumnToggleItem(inStockColumn);
|
||||
HorizontalLayout toolbar = new HorizontalLayout(comicFilter, addIssueButton, menuButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
private void saveIssue(IssueForm.SaveEvent event) {
|
||||
service.saveIssue(event.getIssue());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteIssue(IssueForm.DeleteEvent event) {
|
||||
service.deleteIssue(event.getIssue());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
public void editIssue(Issue issue) {
|
||||
if (issue == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setIssue(issue);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setIssue(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addIssue() {
|
||||
grid.asSingleSelect().clear();
|
||||
editIssue(new Issue());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllIssuesForComic(comicFilter.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
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.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.comics.data.Publisher;
|
||||
|
||||
public class PublisherForm extends FormLayout {
|
||||
public TextField name = new TextField("Name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Publisher> binder = new BeanValidationBinder<>(Publisher.class);
|
||||
|
||||
public PublisherForm() {
|
||||
addClassName("publisher-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
add(name, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setPublisher(Publisher publisher) {
|
||||
binder.setBean(publisher);
|
||||
}
|
||||
|
||||
public abstract static class PublisherFormEvent extends ComponentEvent<PublisherForm> {
|
||||
private Publisher publisher;
|
||||
|
||||
protected PublisherFormEvent(PublisherForm source, Publisher publisher) {
|
||||
super(source, false);
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
public Publisher getPublisher() {
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends PublisherFormEvent {
|
||||
SaveEvent(PublisherForm source, Publisher publisher) {
|
||||
super(source, publisher);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends PublisherFormEvent {
|
||||
DeleteEvent(PublisherForm source, Publisher publisher) {
|
||||
super(source, publisher);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends PublisherFormEvent {
|
||||
CloseEvent(PublisherForm 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,130 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.Publisher;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.PUBLISHER_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Publisher | Comics | Kontor")
|
||||
public class PublisherView extends VerticalLayout {
|
||||
|
||||
Grid<Publisher> grid = new Grid<>(Publisher.class);
|
||||
TextField filterText = new TextField();
|
||||
PublisherForm form;
|
||||
|
||||
ComicService service;
|
||||
|
||||
public PublisherView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("publisher-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("publisher-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editPublisher(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new PublisherForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::savePublisher);
|
||||
form.addDeleteListener(this::deletePublisher);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void savePublisher(PublisherForm.SaveEvent event) {
|
||||
service.savePublisher(event.getPublisher());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deletePublisher(PublisherForm.DeleteEvent event) {
|
||||
service.deletePublisher(event.getPublisher());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
public Grid<Publisher> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public PublisherForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addPublisherButton = new Button("Add publisher");
|
||||
addPublisherButton.addClickListener(click -> addPublisher());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addPublisherButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editPublisher(Publisher publisher) {
|
||||
if (publisher == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setPublisher(publisher);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setPublisher(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addPublisher() {
|
||||
grid.asSingleSelect().clear();
|
||||
editPublisher(new Publisher());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllPublishers(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
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.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.StoryArc;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StoryArcForm extends FormLayout {
|
||||
|
||||
ComboBox<Comic> comic = new ComboBox<>("Comic");
|
||||
TextField name = new TextField("Story Arc Name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<StoryArc> binder = new BeanValidationBinder<>(StoryArc.class);
|
||||
|
||||
public StoryArcForm(List<Comic> comics) {
|
||||
addClassName("storyarc-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comic.setItems(comics);
|
||||
comic.setItemLabelGenerator(Comic::getTitle);
|
||||
add(comic, name, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setStoryArc(StoryArc storyArc) {
|
||||
binder.setBean(storyArc);
|
||||
}
|
||||
|
||||
public abstract static class StoryArcFormEvent extends ComponentEvent<StoryArcForm> {
|
||||
private StoryArc storyArc;
|
||||
|
||||
protected StoryArcFormEvent(StoryArcForm source, StoryArc storyArc) {
|
||||
super(source, false);
|
||||
this.storyArc = storyArc;
|
||||
}
|
||||
|
||||
public StoryArc getStoryArc() {
|
||||
return storyArc;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends StoryArcFormEvent {
|
||||
SaveEvent(StoryArcForm source, StoryArc storyArc) {
|
||||
super(source, storyArc);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends StoryArcFormEvent {
|
||||
DeleteEvent(StoryArcForm source, StoryArc storyArc) {
|
||||
super(source, storyArc);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends StoryArcFormEvent {
|
||||
CloseEvent(StoryArcForm 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,130 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
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.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.StoryArc;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.STORYARC_ROTE, layout = MainLayout.class)
|
||||
@PageTitle("StoryArc | Comics | Kontor")
|
||||
public class StoryArcView extends VerticalLayout {
|
||||
|
||||
Grid<StoryArc> grid = new Grid<>(StoryArc.class);
|
||||
ComboBox<Comic> comicFilter = new ComboBox<>("Comic");
|
||||
StoryArcForm form;
|
||||
ComicService service;
|
||||
|
||||
public StoryArcView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("storyarc-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
StoryArcForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
public Grid<StoryArc> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("storyarc-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("comic.title", "name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editStoryArc(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new StoryArcForm(service.findAllComics(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveStoryArc);
|
||||
form.addDeleteListener(this::deleteStoryArc);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveStoryArc(StoryArcForm.SaveEvent event) {
|
||||
service.saveStoryArc(event.getStoryArc());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteStoryArc(StoryArcForm.DeleteEvent event) {
|
||||
service.deleteStoryArc(event.getStoryArc());
|
||||
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() {
|
||||
comicFilter.setItems(service.findAllComics(null));
|
||||
comicFilter.setItemLabelGenerator(Comic::getTitle);
|
||||
comicFilter.addValueChangeListener(e -> updateList());
|
||||
comicFilter.setClearButtonVisible(true);
|
||||
|
||||
Button addStoryArcButton = new Button("Add StoryArc", click -> addStoryArc());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(comicFilter, addStoryArcButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editStoryArc(StoryArc storyArc) {
|
||||
if (storyArc == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setStoryArc(storyArc);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setStoryArc(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addStoryArc() {
|
||||
grid.asSingleSelect().clear();
|
||||
editStoryArc(new StoryArc());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllStoryArcsForComic(comicFilter.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
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.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.TradePaperback;
|
||||
|
||||
public class TradePaperBackForm extends FormLayout {
|
||||
TextField name = new TextField("Name");
|
||||
ComboBox<Comic> comic = new ComboBox<>("Comic");
|
||||
TextField issueStart = new TextField("Issue Start");
|
||||
TextField issueEnd = new TextField("Issue End");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<TradePaperback> binder = new BeanValidationBinder<>(TradePaperback.class);
|
||||
|
||||
public TradePaperBackForm(List<Comic> comics) {
|
||||
addClassName("tradepaperback-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comic.setItems(comics);
|
||||
comic.setItemLabelGenerator(Comic::getTitle);
|
||||
add(name, comic, issueStart, issueEnd, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setTradePaperBack(TradePaperback tradepaperback) {
|
||||
binder.setBean(tradepaperback);
|
||||
}
|
||||
|
||||
public abstract static class TradePaperBackFormEvent extends ComponentEvent<TradePaperBackForm> {
|
||||
private TradePaperback tradepaperback;
|
||||
|
||||
protected TradePaperBackFormEvent(TradePaperBackForm source, TradePaperback tradepaperback) {
|
||||
super(source, false);
|
||||
this.tradepaperback = tradepaperback;
|
||||
}
|
||||
|
||||
public TradePaperback getTradePaperBack() {
|
||||
return tradepaperback;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends TradePaperBackFormEvent {
|
||||
SaveEvent(TradePaperBackForm source, TradePaperback tradepaperback) {
|
||||
super(source, tradepaperback);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends TradePaperBackFormEvent {
|
||||
DeleteEvent(TradePaperBackForm source, TradePaperback tradepaperback) {
|
||||
super(source, tradepaperback);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends TradePaperBackFormEvent {
|
||||
CloseEvent(TradePaperBackForm 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,129 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.TradePaperback;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.TPB_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("TradePaperBack | Comics | Kontor")
|
||||
public class TradePaperbackView extends VerticalLayout {
|
||||
|
||||
Grid<TradePaperback> grid = new Grid<>(TradePaperback.class);
|
||||
TextField filterText = new TextField();
|
||||
TradePaperBackForm form;
|
||||
ComicService service;
|
||||
|
||||
public TradePaperbackView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("tradepaperback-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
public Grid<TradePaperback> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("tradepaperback-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name", "comic.title", "issueStart", "issueEnd");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editTradePaperBack(event.getValue()));
|
||||
}
|
||||
|
||||
public TradePaperBackForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new TradePaperBackForm(service.findAllComics(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveTradePaperBack);
|
||||
form.addDeleteListener(this::deleteTradePaperBack);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveTradePaperBack(TradePaperBackForm.SaveEvent event) {
|
||||
service.saveTradePaperBack(event.getTradePaperBack());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteTradePaperBack(TradePaperBackForm.DeleteEvent event) {
|
||||
service.deleteTradePaperBack(event.getTradePaperBack());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addTradePaperBackButton = new Button("Add TradePaperBack");
|
||||
addTradePaperBackButton.addClickListener(click -> addTradePaperBack());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addTradePaperBackButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editTradePaperBack(TradePaperback tradepaperback) {
|
||||
if (tradepaperback == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setTradePaperBack(tradepaperback);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setTradePaperBack(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addTradePaperBack() {
|
||||
grid.asSingleSelect().clear();
|
||||
editTradePaperBack(new TradePaperback());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllTradePaperbacks(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.combobox.ComboBox;
|
||||
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.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.StoryArc;
|
||||
import de.thpeetz.kontor.comics.data.Volume;
|
||||
|
||||
public class VolumeForm extends FormLayout {
|
||||
|
||||
ComboBox<Comic> comic = new ComboBox<>("Comic");
|
||||
public TextField name = new TextField("Name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Volume> binder = new BeanValidationBinder<>(Volume.class);
|
||||
|
||||
public VolumeForm(List<Comic> comics) {
|
||||
addClassName("volume-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comic.setItems(comics);
|
||||
comic.setItemLabelGenerator(Comic::getTitle);
|
||||
add(comic, name, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setVolume(Volume volume) {
|
||||
binder.setBean(volume);
|
||||
}
|
||||
|
||||
public abstract static class VolumeFormEvent extends ComponentEvent<VolumeForm> {
|
||||
private Volume volume;
|
||||
|
||||
protected VolumeFormEvent(VolumeForm source, Volume volume) {
|
||||
super(source, false);
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
public Volume getVolume() {
|
||||
return volume;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends VolumeFormEvent {
|
||||
SaveEvent(VolumeForm source, Volume volume) {
|
||||
super(source, volume);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends VolumeFormEvent {
|
||||
DeleteEvent(VolumeForm source, Volume volume) {
|
||||
super(source, volume);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends VolumeFormEvent {
|
||||
CloseEvent(VolumeForm 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,130 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
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.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.Comic;
|
||||
import de.thpeetz.kontor.comics.data.Volume;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.VOLUME_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Volume | Comics | Kontor")
|
||||
public class VolumeView extends VerticalLayout {
|
||||
|
||||
Grid<Volume> grid = new Grid<>(Volume.class);
|
||||
ComboBox<Comic> comicFilter = new ComboBox<>("Comic");
|
||||
VolumeForm form;
|
||||
ComicService service;
|
||||
|
||||
public VolumeView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("volume-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
VolumeForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
public Grid<Volume> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("volume-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("comic.title", "name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editVolume(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new VolumeForm(service.findAllComics(null));
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveVolume);
|
||||
form.addDeleteListener(this::deleteVolume);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveVolume(VolumeForm.SaveEvent event) {
|
||||
service.saveVolume(event.getVolume());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteVolume(VolumeForm.DeleteEvent event) {
|
||||
service.deleteVolume(event.getVolume());
|
||||
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() {
|
||||
comicFilter.setItems(service.findAllComics(null));
|
||||
comicFilter.setItemLabelGenerator(Comic::getTitle);
|
||||
comicFilter.addValueChangeListener(e -> updateList());
|
||||
comicFilter.setClearButtonVisible(true);
|
||||
|
||||
Button addVolumeButton = new Button("Add Volume", click -> addVolume());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(comicFilter, addVolumeButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editVolume(Volume volume) {
|
||||
if (volume == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setVolume(volume);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setVolume(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addVolume() {
|
||||
grid.asSingleSelect().clear();
|
||||
editVolume(new Volume());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllVolumesForComic(comicFilter.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
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.comics.data.ComicWork;
|
||||
import de.thpeetz.kontor.comics.data.Worktype;
|
||||
|
||||
public class WorktypeForm extends FormLayout {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WorktypeForm.class);
|
||||
|
||||
TextField name = new TextField("Name");
|
||||
Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class);
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Worktype> binder = new BeanValidationBinder<>(Worktype.class);
|
||||
|
||||
public WorktypeForm() {
|
||||
addClassName("worktype-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
comicWorks.setColumns("comic.title", "artist.name");
|
||||
comicWorks.getColumnByKey("comic.title").setHeader("Comic");
|
||||
comicWorks.getColumnByKey("artist.name").setHeader("Artist");
|
||||
comicWorks.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
|
||||
add(name, comicWorks, 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(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setWorktype(Worktype worktype) {
|
||||
binder.setBean(worktype);
|
||||
}
|
||||
|
||||
public void setComicWorks(List<ComicWork> works) {
|
||||
log.info("Setting comic works: {}", works);
|
||||
this.comicWorks.setItems(works);
|
||||
}
|
||||
|
||||
public abstract static class WorktypeFormEvent extends ComponentEvent<WorktypeForm> {
|
||||
private Worktype worktype;
|
||||
|
||||
protected WorktypeFormEvent(WorktypeForm source, Worktype worktype) {
|
||||
super(source, false);
|
||||
this.worktype = worktype;
|
||||
}
|
||||
|
||||
public Worktype getWorktype() {
|
||||
return worktype;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends WorktypeFormEvent {
|
||||
SaveEvent(WorktypeForm source, Worktype worktype) {
|
||||
super(source, worktype);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends WorktypeFormEvent {
|
||||
DeleteEvent(WorktypeForm source, Worktype worktype) {
|
||||
super(source, worktype);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends WorktypeFormEvent {
|
||||
CloseEvent(WorktypeForm 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,130 @@
|
||||
package de.thpeetz.kontor.comics.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
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.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.comics.ComicConstants;
|
||||
import de.thpeetz.kontor.comics.data.Worktype;
|
||||
import de.thpeetz.kontor.comics.services.ComicService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@PermitAll
|
||||
@Route(value = ComicConstants.WORKTYPE_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Worktype | Comics | Kontor")
|
||||
public class WorktypeView extends VerticalLayout {
|
||||
|
||||
Grid<Worktype> grid = new Grid<>(Worktype.class);
|
||||
TextField filterText = new TextField();
|
||||
WorktypeForm form;
|
||||
ComicService service;
|
||||
|
||||
public WorktypeView(ComicService service) {
|
||||
this.service = service;
|
||||
addClassName("worktype-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
public Grid<Worktype> getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("worktype-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editWorktype(event.getValue()));
|
||||
}
|
||||
|
||||
public WorktypeForm getForm() {
|
||||
return form;
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new WorktypeForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveWorktype);
|
||||
form.addDeleteListener(this::deleteWorktype);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveWorktype(WorktypeForm.SaveEvent event) {
|
||||
service.saveWorktype(event.getWorktype());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteWorktype(WorktypeForm.DeleteEvent event) {
|
||||
service.deleteWorktype(event.getWorktype());
|
||||
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() {
|
||||
filterText.setPlaceholder("Filter by name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
|
||||
Button addWorktypeButton = new Button("Add worktype");
|
||||
addWorktypeButton.addClickListener(click -> addWorktype());
|
||||
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addWorktypeButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editWorktype(Worktype worktype) {
|
||||
if (worktype == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setWorktype(worktype);
|
||||
form.setComicWorks(worktype.getComicWorks());
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
private void closeEditor() {
|
||||
form.setWorktype(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addWorktype() {
|
||||
grid.asSingleSelect().clear();
|
||||
editWorktype(new Worktype());
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
grid.setItems(service.findAllWorktypes(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user