This commit is contained in:
Francesco 2023-09-18 16:28:10 +02:00
parent c0801cc69d
commit 0bd5ce19f1
6 changed files with 74 additions and 13 deletions

View File

@ -95,7 +95,6 @@ public class DbAdmin {
field.setSchema(schema); field.setSchema(schema);
schema.addField(field); schema.addField(field);
System.out.println(field);
} }
return schema; return schema;

View File

@ -0,0 +1,11 @@
package tech.ailef.dbadmin.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Filterable {
}

View File

@ -45,6 +45,10 @@ import tech.ailef.dbadmin.exceptions.InvalidPageException;
* - Pagination in one to many results? * - Pagination in one to many results?
* - BLOB upload (WIP: check edit not working) * - BLOB upload (WIP: check edit not working)
* - AI console (PRO) * - AI console (PRO)
* - Action logs
* - Boolean icons
* - @Filterable
* - Boolean in create/edit is checkbox
* - SQL console (PRO) * - SQL console (PRO)
* - JPA Validation (PRO) * - JPA Validation (PRO)
* - Logging * - Logging

View File

@ -74,4 +74,20 @@ public class AdvancedJpaRepository extends SimpleJpaRepository {
return entityManager.createQuery(query).setMaxResults(pageSize) return entityManager.createQuery(query).setMaxResults(pageSize)
.setFirstResult((page - 1) * pageSize).getResultList(); .setFirstResult((page - 1) * pageSize).getResultList();
} }
public List<Object> distinctFieldValues(DbField field) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
Class<?> outputType = field.getType().getJavaClass();
if (field.getConnectedType() != null) {
outputType = field.getConnectedSchema().getPrimaryKey().getType().getJavaClass();
}
CriteriaQuery query = cb.createQuery(outputType);
Root root = query.from(schema.getJavaClass());
query.select(root.get(field.getJavaName()).as(outputType)).distinct(true);
return entityManager.createQuery(query).getResultList();
}
} }

View File

@ -1,6 +1,7 @@
package tech.ailef.dbadmin.dbmapping; package tech.ailef.dbadmin.dbmapping;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -19,6 +20,7 @@ import jakarta.persistence.OneToMany;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import tech.ailef.dbadmin.DbAdmin; import tech.ailef.dbadmin.DbAdmin;
import tech.ailef.dbadmin.annotations.ComputedColumn; import tech.ailef.dbadmin.annotations.ComputedColumn;
import tech.ailef.dbadmin.annotations.Filterable;
import tech.ailef.dbadmin.exceptions.DbAdminException; import tech.ailef.dbadmin.exceptions.DbAdminException;
import tech.ailef.dbadmin.misc.Utils; import tech.ailef.dbadmin.misc.Utils;
@ -173,6 +175,17 @@ public class DbObjectSchema {
public Method getComputedColumn(String name) { public Method getComputedColumn(String name) {
return computedColumns.get(name); return computedColumns.get(name);
} }
public List<DbField> getFilterableFields() {
return getSortedFields().stream().filter(f -> {
return !f.isBinary() && !f.isPrimaryKey()
&& f.getPrimitiveField().getAnnotation(Filterable.class) != null;
}).toList();
}
public List<Object> getFieldValues(DbField field) {
return jpaRepository.distinctFieldValues(field);
}
public Object[] getInsertArray(Map<String, String> params, Map<String, MultipartFile> files) { public Object[] getInsertArray(Map<String, String> params, Map<String, MultipartFile> files) {
int currentIndex = 0; int currentIndex = 0;

View File

@ -15,7 +15,7 @@
<span class="align-middle"> [[ ${schema.getJavaClass().getSimpleName()} ]] </span> <span class="align-middle"> [[ ${schema.getJavaClass().getSimpleName()} ]] </span>
</h1> </h1>
<div class="row mt-4"> <div class="row mt-4">
<div class="col"> <div th:class="${schema.getFilterableFields().isEmpty() ? 'col' : 'col-9'}">
<div class="w-100 d-flex inner-navigation"> <div class="w-100 d-flex inner-navigation">
<a th:href="|/dbadmin/model/${className}|" class="active"> <a th:href="|/dbadmin/model/${className}|" class="active">
<div class="ui-tab ps-5 pe-5 p-3"> <div class="ui-tab ps-5 pe-5 p-3">
@ -31,15 +31,16 @@
</div> </div>
</div> </div>
<div class="box with-navigation"> <div class="box with-navigation">
<form th:action="|/dbadmin/model/${className}|" method="GET" class="mb-3"> <form th:action="|/dbadmin/model/${className}|" method="GET" class="mb-3">
<div class="input-group"> <div class="input-group">
<input type="text" th:value="${query}" <span class="input-group-text"><i class="bi bi-search"></i></span>
placeholder="Type and press ENTER to search" <input type="text" th:value="${query}"
class="ui-text-input form-control" name="query" autofocus> placeholder="Type and press ENTER to search"
<button class="ui-btn btn btn-primary">Search</button> class="ui-text-input form-control" name="query" autofocus>
</div> <button class="ui-btn btn btn-primary">Search</button>
</form> </div>
</form>
<div class="separator mb-4 mt-4"></div>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
@ -57,10 +58,27 @@
th:href="|/dbadmin/model/${schema.getClassName()}/create|"><i class="bi bi-plus-square"></i></a></h3> th:href="|/dbadmin/model/${schema.getClassName()}/create|"><i class="bi bi-plus-square"></i></a></h3>
</div> </div>
<div th:replace="~{fragments/table_selectable :: table(results=${page.getResults()}, schema=${schema})}" <div th:replace="~{fragments/table_selectable :: table(results=${page.getResults()}, schema=${schema})}">
</div>
</div> </div>
</div> </div>
<div th:if="${!schema.getFilterableFields().isEmpty()}" class="col-3">
<div class="box">
<h3 class="fw-bold"><i class="bi bi-funnel"></i> Filters</h3>
<ul>
<li th:each="field : ${schema.getFilterableFields()}">
<span class="fw-bold" th:text="${field.getName()}"></span>
<th:block th:if="${field.getConnectedType() != null}">
<div th:each="val : ${schema.getFieldValues(field)}">
<span th:text="${val}"></span>
</div>
</th:block>
</li>
</ul>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>