Profile settings for view column sort orders
authorelgekko <vasary@elgekko.net>
Sat, 5 Aug 2023 20:33:52 +0000 (22:33 +0200)
committerelgekko <vasary@elgekko.net>
Sat, 5 Aug 2023 20:33:52 +0000 (22:33 +0200)
22 files changed:
.idea/encodings.xml
KB.md
lis-app/src/main/resources/application-dev.yaml
lis-db/migrations/README
lis-db/migrations/scripts/005_create_profile.sql [new file with mode: 0644]
lis-db/src/main/java/hu/user/lis/db/Profile.java [new file with mode: 0644]
lis-db/src/main/java/hu/user/lis/db/repository/ProfileRepository.java [new file with mode: 0644]
lis-services/src/main/java/hu/user/lis/services/data/EntityDataService.java
lis-ui/src/main/java/hu/user/lis/ui/SlyCrmUIProperties.java [new file with mode: 0644]
lis-ui/src/main/java/hu/user/lis/ui/auth/CurrentProfile.java
lis-ui/src/main/java/hu/user/lis/ui/data/CachedSpringDataModel.java
lis-ui/src/main/java/hu/user/lis/ui/view/AssociatesViewModel.java
lis-ui/src/main/java/hu/user/lis/ui/view/LoginViewModel.java
lis-ui/src/main/java/hu/user/lis/ui/view/PartnersViewModel.java
lis-ui/src/main/java/hu/user/lis/ui/view/ProjectsViewModel.java
lis-ui/src/main/java/hu/user/lis/ui/view/ServiceRecordsViewModel.java
lis-ui/src/main/java/hu/user/lis/ui/view/common/EntityViewModel.java
lis-ui/src/main/resources/web/editor/associate-editor.zul
lis-ui/src/main/resources/web/editor/partner-editor.zul
lis-ui/src/main/resources/web/editor/project-editor.zul
lis-ui/src/main/resources/web/login.zul
pom.xml

index 3adb05546106b9c7871b0d4fb9abcd7c1dca54c6..4431c81f5d7aa2acff7bf0185a907024a6cbe4f7 100644 (file)
@@ -2,7 +2,9 @@
 <project version="4">
   <component name="Encoding">
     <file url="file://$PROJECT_DIR$/lis-app/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/lis-app/src/main/resources" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/lis-db/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/lis-db/src/main/resources" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/lis-services/src/main/java" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/lis-ui/src/main/java" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/lis-ui/src/main/resources" charset="UTF-8" />
diff --git a/KB.md b/KB.md
index 2e92b528229651dcfbb0cdd0c7447029a5ef4147..2bb18c4a5004f4b26e5e01fcdd1a43d0ab0fbd14 100644 (file)
--- a/KB.md
+++ b/KB.md
@@ -36,6 +36,7 @@ https://www.baeldung.com/spring-email
 
 ##### ZK
 
+https://www.zkoss.org/documentation#References
 https://www.zkoss.org/wiki/ZK_Configuration_Reference/zk.xml/The_Library_Properties
 https://www.zkoss.org/wiki/ZK_Developer%27s_Reference/Performance_Tips  
 https://www.zkoss.org/wiki/ZK%20Developer%27s%20Reference/Performance%20Tips/Listbox,%20Grid%20and%20Tree%20for%20Huge%20Data/Implement%20ListModel%20and%20TreeModel  
@@ -43,6 +44,8 @@ https://www.zkoss.org/wiki/ZK_Developer%27s_Reference/MVC/Controller/Wire_Variab
 https://www.zkoss.org/wiki/ZK_Client-side_Reference/General_Control/Client-side_selection_of_elements_and_widgets  
 https://www.zkoss.org/wiki/ZK_Developer%27s_Reference/Testing/Testing_Tips  
 https://www.zkoss.org/wiki/Small_Talks/2013/October/ZK_Testing_with_Sahi
+https://zkfiddle.org/sample/3ltrsms/9-Grid-style-7-1
+https://zkfiddle.org/sample/3bmc52p/1-detect-dark-mode
 
 ##### Spring ZK
 
index fe8380907535bdfd13ec368fc166f0d73c4cba75..fe3996683db8cc3a8ba7f80bd15cf7a04349535b 100644 (file)
@@ -24,7 +24,12 @@ spring:
 logging:
   level:
     org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR
-#    org.springframework.security: DEBUG
+hu:
+  user-ibm:
+    sly-crm:
+      ui:
+        user-name: user
+        password: password
 #    org.springframework.security.web: INFO
 #  pattern:
 #    console: "%d %-5level %logger : %msg%n"
index 641e4e94692b7b2f3739561362410a56c0bd07eb..8dcc3a6f66a4bd87e4eaee04762672b807e8b5b2 100644 (file)
@@ -48,8 +48,11 @@ Enjoy.
 
 
 DOCKER
-docker run -itd --name lis --privileged=true -p 50000:50000 -p 27017:27017 -e LICENSE=accept -e DB2INSTANCE=db2admin -e DB2INST1_PASSWORD=password -e DBNAME=lis -e PERSISTENT_HOME=true -v /Docker:/database ibmcom/db2
+docker run -itd --name lis --privileged=true -p 50000:50000 -e LICENSE=accept -e DB2INSTANCE=db2admin -e DB2INST1_PASSWORD=password -e DBNAME=lis -e PERSISTENT_HOME=true -v /Docker:/database ibmcom/db2
 docker logs -f lis
 docker exec -it lis bash
 docker stop lis
 docker remove lis
+
+MIGRATE
+migrate new create profile --idpattern=000
diff --git a/lis-db/migrations/scripts/005_create_profile.sql b/lis-db/migrations/scripts/005_create_profile.sql
new file mode 100644 (file)
index 0000000..cfc8ed2
--- /dev/null
@@ -0,0 +1,16 @@
+-- // create profile
+-- Migration SQL that makes the change goes here.
+
+CREATE TABLE profile (
+    id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    login VARCHAR(255),
+    type VARCHAR(255),
+    setting CLOB,
+    CONSTRAINT pk_profile PRIMARY KEY (id)
+);
+CREATE UNIQUE INDEX UDX_PROFILE_LOGIN_TYPE ON PROFILE(LOGIN, TYPE);
+
+-- //@UNDO
+-- SQL to undo the change goes here.
+DROP TABLE profile;
+
diff --git a/lis-db/src/main/java/hu/user/lis/db/Profile.java b/lis-db/src/main/java/hu/user/lis/db/Profile.java
new file mode 100644 (file)
index 0000000..1e800a8
--- /dev/null
@@ -0,0 +1,24 @@
+package hu.user.lis.db;
+
+import lombok.*;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+@Getter
+@Setter
+@Entity
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Profile implements Serializable {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    Long id;
+    String login;
+    String type;
+    String setting;
+}
diff --git a/lis-db/src/main/java/hu/user/lis/db/repository/ProfileRepository.java b/lis-db/src/main/java/hu/user/lis/db/repository/ProfileRepository.java
new file mode 100644 (file)
index 0000000..9da06ba
--- /dev/null
@@ -0,0 +1,17 @@
+package hu.user.lis.db.repository;
+
+import hu.user.lis.db.Profile;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface ProfileRepository extends JpaRepository<Profile, Long> {
+
+    Optional<Profile> findByLoginAndType(String login, String type);
+
+    List<Profile> findAllByLogin(String login);
+
+    void deleteAllByLogin(String login);
+
+}
index bd57725e441db6cf7b99ab9556154e653911c22f..58697ba9e36e6063d422e100975a59b291c91c3a 100644 (file)
@@ -41,6 +41,16 @@ public class EntityDataService<T extends Serializable> extends EntityDataService
         return result;
     }
 
+    public T fromJSON(String data, Class<T> objectClass) {
+        T result = null;
+        try {
+            result = (T) objectMapper.readValue(data, objectClass);
+        } catch (JsonProcessingException e) {
+            log.catching(e);
+        }
+        return result;
+    }
+
     public boolean areEquals(T entity1, T entity2) {
         boolean result = true;
         String json1 = toJSON(entity1);
diff --git a/lis-ui/src/main/java/hu/user/lis/ui/SlyCrmUIProperties.java b/lis-ui/src/main/java/hu/user/lis/ui/SlyCrmUIProperties.java
new file mode 100644 (file)
index 0000000..136c478
--- /dev/null
@@ -0,0 +1,15 @@
+package hu.user.lis.ui;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Getter
+@Setter
+@Component
+@ConfigurationProperties(prefix = "hu.user-ibm.sly-crm.ui")
+public class SlyCrmUIProperties {
+    String userName;
+    String password;
+}
index a8700fed43860a20ad2c0f3de2ff7aeb45352cf1..8402070c2bf8b4b3e5ffec6717027a22da32ac42 100644 (file)
@@ -1,16 +1,48 @@
 package hu.user.lis.ui.auth;
 
 import hu.user.lis.db.Associate;
+import hu.user.lis.db.Profile;
+import hu.user.lis.db.repository.ProfileRepository;
 import lombok.Getter;
-import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
 @Service
-@Getter
-@Setter
 public class CurrentProfile {
+    @Autowired
+    ProfileRepository profileRepository;
+    @Getter
+    Associate associate;
+
+    @Getter
+    Map<String, Profile> settings = new HashMap<>();
+
+    public void setAssociate(Associate associate) {
+        this.associate = associate;
+        loadSettings();
+    }
+
+    private void loadSettings() {
+        List<Profile> profileSettings = profileRepository.findAllByLogin(associate.getLogin());
+        settings = profileSettings.stream().collect(Collectors.toMap(Profile::getType, p -> p));
+    }
 
-    private Associate associate;
+    public Profile getSetting(String type) {
+        return settings.get(type);
+    }
 
-    
+    public void addSetting(Profile columnProfile) {
+        Profile existing = settings.get(columnProfile.getType());
+        if (Objects.nonNull(existing)) {
+            columnProfile.setId(existing.getId());
+        }
+        settings.put(columnProfile.getType(), columnProfile);
+        profileRepository.save(columnProfile);
+    }
 }
index 3c491d7725eb84eaf2ca93e978cccedb72be3a51..8e000b98b0433a0f03ecee1257a4b407a83e8cee 100644 (file)
@@ -1,8 +1,12 @@
 package hu.user.lis.ui.data;
 
+import hu.user.lis.db.Profile;
+import hu.user.lis.services.data.EntityDataService;
+import hu.user.lis.ui.auth.CurrentProfile;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
@@ -10,6 +14,9 @@ import org.springframework.stereotype.Component;
 import org.zkoss.json.JSONObject;
 import org.zkoss.zul.FieldComparator;
 
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Objects;
 
 @Component
@@ -18,12 +25,37 @@ public abstract class CachedSpringDataModel<T> extends CachedDataModel<T> {
 
     @Getter
     @Setter
-    JSONObject cols = new JSONObject();
+    JSONObject columnSettings = new JSONObject();
 
-    public void addColumn(String name, String direction) {
+    @Autowired
+    CurrentProfile currentProfile;
+
+    @Autowired
+    EntityDataService<JSONObject> entityDataService;
+
+    public void addColumns(Map<String, String> columns) {
+        Profile profile = currentProfile.getSetting(getClass().getSimpleName());
+        if (Objects.isNull(profile)) {
+            columns.keySet().forEach(colName -> addColumn(colName, columns.get(colName)));
+            saveProfileSetting();
+        } else {
+            columnSettings = entityDataService.fromJSON(profile.getSetting(), JSONObject.class);
+        }
+    }
+
+    private void saveProfileSetting() {
+        Profile columnProfile = Profile.builder()
+                .login(currentProfile.getAssociate().getLogin())
+                .type(getClass().getSimpleName())
+                .setting(entityDataService.toJSON(columnSettings))
+                .build();
+        currentProfile.addSetting(columnProfile);
+    }
+
+    private void addColumn(String name, String direction) {
         JSONObject sort = new JSONObject();
         sort.put("sortDirection", direction);
-        cols.put(name, sort);
+        columnSettings.put(name, sort);
 
         if (!direction.equals(NATURAL)) {
             setSortComparator(new FieldComparator(name, direction.equals(ASCENDING)));
@@ -42,5 +74,23 @@ public abstract class CachedSpringDataModel<T> extends CachedDataModel<T> {
         log.info("{} {}", getClass().getSimpleName(), pageable);
         return pageable;
     }
+
+    @Override
+    public void sort(Comparator<T> cmpr, boolean ascending) {
+        super.sort(cmpr, ascending);
+
+        FieldComparator sortComparator = (FieldComparator) cmpr;
+        columnSettings.keySet().forEach(colName -> {
+            LinkedHashMap<String, String> col = (LinkedHashMap<String, String>) columnSettings.get(colName);
+            if (colName.equals(sortComparator.getRawOrderBy())) {
+                col.put("sortDirection", ascending ? ASCENDING : DESCENDING);
+            } else {
+                col.put("sortDirection", NATURAL);
+            }
+        });
+        saveProfileSetting();
+        log.info("Sort settings for {} : {}", getClass().getSimpleName(), columnSettings.toJSONString());
+    }
+
 }
 
index 834be1bb71fc3a1643476cbfc198df321100f6df..2070dfd9d9486576462bf1227168dffe77ee6339 100644 (file)
@@ -1,5 +1,6 @@
 package hu.user.lis.ui.view;
 
+import com.google.common.collect.ImmutableMap;
 import hu.user.lis.db.Associate;
 import hu.user.lis.ui.Constants;
 import hu.user.lis.ui.data.AssociatesDataModel;
@@ -34,9 +35,11 @@ public class AssociatesViewModel extends FilterActiveViewModel<Associate> {
     @Init
     public void init() {
         super.init();
-        addColumn("name", ASCENDING);
-        addColumn("login", NATURAL);
-        addColumn("active", NATURAL);
+        addColumns(ImmutableMap.of(
+                "name", ASCENDING,
+                "login", NATURAL,
+                "active", NATURAL
+        ));
     }
 
 
index b2075f9f6827aaf263fe5e610c220e4a3e0676f5..579cdee43a4750c5dc21c6a5bc4befc8372c9904 100644 (file)
@@ -1,5 +1,6 @@
 package hu.user.lis.ui.view;
 
+import hu.user.lis.ui.SlyCrmUIProperties;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.boot.info.BuildProperties;
@@ -13,6 +14,9 @@ public class LoginViewModel {
     @WireVariable
     BuildProperties buildProperties;
 
+    @WireVariable
+    SlyCrmUIProperties slyCrmUIProperties;
+
     public LoginViewModel() {
 
     }
index a7030bc43d9f38321265395d182434bed0e17cb1..d2e51c3995f2a9beb5b89479413e7d92a26f8d31 100644 (file)
@@ -1,5 +1,6 @@
 package hu.user.lis.ui.view;
 
+import com.google.common.collect.ImmutableMap;
 import hu.user.lis.db.Partner;
 import hu.user.lis.ui.Constants;
 import hu.user.lis.ui.data.CachedSpringDataModel;
@@ -34,10 +35,12 @@ public class PartnersViewModel extends FilterActiveViewModel<Partner> {
     @Init
     public void init() {
         super.init();
-        addColumn("name", ASCENDING);
-        addColumn("vatNr", NATURAL);
-        addColumn("address", NATURAL);
-        addColumn("active", NATURAL);
+        addColumns(ImmutableMap.of(
+                "name", ASCENDING,
+                "vatNr", NATURAL,
+                "address", NATURAL,
+                "active", NATURAL
+        ));
     }
 
     protected void refresh() {
index e5ea839d13fdde6e38561c3e2d02282c45c7a2d7..8e31c076c8783714995fea9e49944143261cb840 100644 (file)
@@ -1,5 +1,6 @@
 package hu.user.lis.ui.view;
 
+import com.google.common.collect.ImmutableMap;
 import hu.user.lis.db.Project;
 import hu.user.lis.ui.Constants;
 import hu.user.lis.ui.data.CachedSpringDataModel;
@@ -44,12 +45,14 @@ public class ProjectsViewModel extends FilterActiveViewModel<Project> implements
     public void init() {
         super.init();
         eventBus.register(this);
-        addColumn("humanId", ASCENDING);
-        addColumn("partner.name", NATURAL);
-        addColumn("projectStatus.name", NATURAL);
-        addColumn("name", NATURAL);
-        addColumn("contactName", NATURAL);
-        addColumn("active", NATURAL);
+        addColumns(ImmutableMap.of(
+                "humanId", ASCENDING,
+                "partner.name", NATURAL,
+                "projectStatus.name", NATURAL,
+                "name", NATURAL,
+                "contactName", NATURAL,
+                "active", NATURAL
+        ));
     }
 
     protected void refresh() {
index 03b69b6e80d4458a480745460a86a4a3fe1434eb..ca91a4fa47e203a400a2982f95f2f3b222dde6ca 100644 (file)
@@ -1,5 +1,6 @@
 package hu.user.lis.ui.view;
 
+import com.google.common.collect.ImmutableMap;
 import hu.user.lis.db.Associate;
 import hu.user.lis.db.Project;
 import hu.user.lis.db.ServiceRecord;
@@ -65,13 +66,15 @@ public class ServiceRecordsViewModel extends EntityViewModel<ServiceRecord> impl
         super.init();
         eventBus.register(this);
         eventBus.registerForBinding(this);
-        addColumn("project.humanId", ASCENDING);
-        addColumn("project.name", NATURAL);
-        addColumn("project.partner.name", NATURAL);
-        addColumn("associate.name", NATURAL);
-        addColumn("workDay", NATURAL);
-        addColumn("description", NATURAL);
-        addColumn("workHours", NATURAL);
+        addColumns(ImmutableMap.of(
+                "project.humanId", ASCENDING,
+                "project.name", NATURAL,
+                "project.partner.name", NATURAL,
+                "associate.name", NATURAL,
+                "workDay", NATURAL,
+                "description", NATURAL,
+                "workHours", NATURAL
+        ));
     }
 
     @AfterCompose
index 97b261b136a4f3e7b471199cea4d8f0084f8c155..578cad2b7c3f45ea0b3197747bd721d2b61f7f1b 100644 (file)
@@ -16,6 +16,7 @@ import org.zkoss.zk.ui.util.Clients;
 import org.zkoss.zkplus.spring.DelegatingVariableResolver;
 
 import java.io.Serializable;
+import java.util.Map;
 import java.util.Set;
 
 
@@ -31,14 +32,14 @@ public abstract class EntityViewModel<T extends Serializable> {
     @WireVariable
     EntityDataService<T> entityDataService;
 
-    protected void addColumn(String name, String direction) {
-        getDataModel().addColumn(name, direction);
+    protected void addColumns(Map<String, String> columns) {
+        getDataModel().addColumns(columns);
     }
 
     public JSONObject getCols() {
-        return getDataModel().getCols();
+        return getDataModel().getColumnSettings();
     }
-    
+
     abstract protected CachedSpringDataModel<T> getDataModel();
 
     @AfterCompose
index 789140602daca7ec343f850689c24a48470a1c8f..49bbae4fb675c35be8d0c8c41bdc018c15bba183 100644 (file)
                     <tabpanels>
                         <tabpanel>
                             <vlayout hflex="true">
+
                                 <label value="Név"/>
                                 <textbox hflex="true" instant="true" value="@bind(vm.formDocument.name) @validator(vm)"
                                          forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
+                                <label value="@load(self.previousSibling)"/>
+                                <!--                                <label value="@bind(vmsgs[self.previousSibling])"/>-->
+
                                 <label value="Login"/>
                                 <textbox hflex="true" instant="true" value="@bind(vm.formDocument.login) @validator(vm)"
                                          forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
index 91ec89516140c535a29e8835b3e428d1c2a558eb..82a2ecf50573493cfc7d654cf16e8d3d9569c996 100644 (file)
@@ -1,7 +1,7 @@
 <?link rel="stylesheet" type="text/css" href="~./static/css/webclient.css" ?>
 <zk>
     <window id="partnerPopup" width="60%" height="400px" closable="true"
-            viewModel="@id('vm') @init('hu.user.lis.ui.editor.PartnerEditorModel')">
+            viewModel="@id('vm') @init('hu.user.lis.ui.editor.PartnerEditorModel')" validationMessages="@id('vmsgs')">
         <caption label="Partner szerkesztés"/>
         <!--        <w:script type="text/javascript" src="~./static/js/cleave.min.js"/>-->
         <borderlayout>
index ab4deae8de2a8d808e73fbec5c2f1c2c85b56491..79b99600868eff99d7bfcb6c8ddbb1f4f032e443 100644 (file)
@@ -1,8 +1,7 @@
 <?component name="entity-selector" inline="true" class="hu.user.lis.ui.editor.widget.EntitySelector"?>
 <zk>
     <window id="projectEditor" hflex="true" vflex="true"
-            viewModel="@id('vm') @init('hu.user.lis.ui.editor.ProjectEditorModel')"
-            validationMessages="@id('vmsgs')">
+            viewModel="@id('vm') @init('hu.user.lis.ui.editor.ProjectEditorModel')">
         <caption label="Projekt szerkesztés"/>
         <borderlayout>
             <center id="centerPanel" border="none" vflex="true" hflex="true" autoscroll="true">
@@ -47,7 +46,6 @@
                                                         <textbox instant="true" width="100%"
                                                                  value="@bind(vm.formDocument.contactName) @validator(vm)"
                                                                  forward="onOK=submit.onClick, onCancel=cancel.onClick"/>
-                                                        <label value="@bind(vmsgs[self.previousSibling])"/>
                                                     </vlayout>
                                                 </row>
                                                 <row>
index eb0f59f7db75faec9529658c7709488e1b496c14..fea01b5136746070069168bd37b795e676447248 100644 (file)
                 <rows>
                     <row>
                         <label value="User"/>
-                        <textbox name="username" hflex="true"/>
+                        <textbox name="username" hflex="true" value="@load(vm.slyCrmUIProperties.userName)"/>
                     </row>
                     <row>
                         <label value="Password"/>
-                        <textbox type="password" name="password" hflex="true"/>
+                        <textbox type="password" name="password" hflex="true"
+                                 value="@load(vm.slyCrmUIProperties.password)"/>
                     </row>
                     <row spans="2" align="right">
                         <hlayout>
diff --git a/pom.xml b/pom.xml
index 3226f9dde1f2f730dbcd0cc19bb8deb0aa78e427..f5cc24834090d0643ef15bf4c64d9a2c60146703 100644 (file)
--- a/pom.xml
+++ b/pom.xml
             <artifactId>commons-lang3</artifactId>
             <version>3.12.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.4</version>
+        </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>