mirror of
https://github.com/dalbodeule/snap-admin.git
synced 2025-06-09 05:48:20 +00:00
- Small refactor to the rendering part for input fileds: each field now has its own Thymeleaf
fragment in order to allow easier customization and easier support for different field types (required for #7) - WIP Handle unsupported types gracefully (#9)
This commit is contained in:
parent
bebc562961
commit
4177bdcd43
@ -52,7 +52,9 @@ import tech.ailef.dbadmin.external.dbmapping.CustomJpaRepository;
|
|||||||
import tech.ailef.dbadmin.external.dbmapping.DbField;
|
import tech.ailef.dbadmin.external.dbmapping.DbField;
|
||||||
import tech.ailef.dbadmin.external.dbmapping.DbFieldType;
|
import tech.ailef.dbadmin.external.dbmapping.DbFieldType;
|
||||||
import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema;
|
import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema;
|
||||||
|
import tech.ailef.dbadmin.external.dto.MappingError;
|
||||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||||
|
import tech.ailef.dbadmin.external.exceptions.UnsupportedFieldTypeException;
|
||||||
import tech.ailef.dbadmin.external.misc.Utils;
|
import tech.ailef.dbadmin.external.misc.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -174,17 +176,21 @@ public class DbAdmin {
|
|||||||
CustomJpaRepository simpleJpaRepository = new CustomJpaRepository(schema, entityManager);
|
CustomJpaRepository simpleJpaRepository = new CustomJpaRepository(schema, entityManager);
|
||||||
schema.setJpaRepository(simpleJpaRepository);
|
schema.setJpaRepository(simpleJpaRepository);
|
||||||
|
|
||||||
|
|
||||||
logger.debug("Processing class: " + klass + " - Table: " + schema.getTableName());
|
logger.debug("Processing class: " + klass + " - Table: " + schema.getTableName());
|
||||||
|
|
||||||
Field[] fields = klass.getDeclaredFields();
|
Field[] fields = klass.getDeclaredFields();
|
||||||
for (Field f : fields) {
|
for (Field f : fields) {
|
||||||
DbField field = mapField(f, schema);
|
try {
|
||||||
if (field == null) {
|
DbField field = mapField(f, schema);
|
||||||
throw new DbAdminException("Impossible to map field: " + f);
|
field.setSchema(schema);
|
||||||
|
schema.addField(field);
|
||||||
|
} catch (UnsupportedFieldTypeException e) {
|
||||||
|
schema.addError(
|
||||||
|
new MappingError(
|
||||||
|
"The class contains the field `" + f.getName() + "` of type `" + f.getType().getSimpleName() + "`, which is not supported"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
field.setSchema(schema);
|
|
||||||
schema.addField(field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Processed " + klass + ", extracted " + schema.getSortedFields().size() + " fields");
|
logger.debug("Processed " + klass + ", extracted " + schema.getSortedFields().size() + " fields");
|
||||||
@ -280,7 +286,7 @@ public class DbAdmin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fieldType == null) {
|
if (fieldType == null) {
|
||||||
throw new DbAdminException("Unable to determine fieldType for " + f.getType());
|
throw new UnsupportedFieldTypeException("Unable to determine fieldType for " + f.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayFormat displayFormat = f.getAnnotation(DisplayFormat.class);
|
DisplayFormat displayFormat = f.getAnnotation(DisplayFormat.class);
|
||||||
|
@ -123,29 +123,29 @@ public enum DbFieldType {
|
|||||||
return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT);
|
return List.of(CompareOperator.GT, CompareOperator.EQ, CompareOperator.LT);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OFFSET_DATE_TIME {
|
// OFFSET_DATE_TIME {
|
||||||
@Override
|
// @Override
|
||||||
public String getFragmentName(FragmentContext c) {
|
// public String getFragmentName(FragmentContext c) {
|
||||||
return "offset_datetime";
|
// return "text";
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public Object parseValue(Object value) {
|
// public Object parseValue(Object value) {
|
||||||
if (value == null) return null;
|
// if (value == null) return null;
|
||||||
return OffsetDateTime.parse(value.toString());
|
// return OffsetDateTime.parse(value.toString());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public Class<?> getJavaClass() {
|
// public Class<?> getJavaClass() {
|
||||||
return OffsetDateTime.class;
|
// return OffsetDateTime.class;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public List<CompareOperator> getCompareOperators() {
|
// public List<CompareOperator> getCompareOperators() {
|
||||||
return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE);
|
// return List.of(CompareOperator.AFTER, CompareOperator.STRING_EQ, CompareOperator.BEFORE);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
},
|
// },
|
||||||
LOCAL_DATE {
|
LOCAL_DATE {
|
||||||
@Override
|
@Override
|
||||||
public String getFragmentName(FragmentContext c) {
|
public String getFragmentName(FragmentContext c) {
|
||||||
@ -450,8 +450,8 @@ public enum DbFieldType {
|
|||||||
return BIG_DECIMAL;
|
return BIG_DECIMAL;
|
||||||
} else if (klass == byte[].class) {
|
} else if (klass == byte[].class) {
|
||||||
return BYTE_ARRAY;
|
return BYTE_ARRAY;
|
||||||
} else if (klass == OffsetDateTime.class) {
|
// } else if (klass == OffsetDateTime.class) {
|
||||||
return OFFSET_DATE_TIME;
|
// return OFFSET_DATE_TIME;
|
||||||
} else {
|
} else {
|
||||||
throw new DbAdminException("Unsupported field type: " + klass);
|
throw new DbAdminException("Unsupported field type: " + klass);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import jakarta.persistence.Table;
|
|||||||
import tech.ailef.dbadmin.external.DbAdmin;
|
import tech.ailef.dbadmin.external.DbAdmin;
|
||||||
import tech.ailef.dbadmin.external.annotations.ComputedColumn;
|
import tech.ailef.dbadmin.external.annotations.ComputedColumn;
|
||||||
import tech.ailef.dbadmin.external.annotations.HiddenColumn;
|
import tech.ailef.dbadmin.external.annotations.HiddenColumn;
|
||||||
|
import tech.ailef.dbadmin.external.dto.MappingError;
|
||||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||||
import tech.ailef.dbadmin.external.misc.Utils;
|
import tech.ailef.dbadmin.external.misc.Utils;
|
||||||
|
|
||||||
@ -79,6 +80,8 @@ public class DbObjectSchema {
|
|||||||
*/
|
*/
|
||||||
private String tableName;
|
private String tableName;
|
||||||
|
|
||||||
|
private List<MappingError> errors = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this schema for the specific `@Entity` class.
|
* Initializes this schema for the specific `@Entity` class.
|
||||||
* Determines the table name from the `@Table` annotation and also
|
* Determines the table name from the `@Table` annotation and also
|
||||||
@ -155,6 +158,10 @@ public class DbObjectSchema {
|
|||||||
return Collections.unmodifiableList(fields);
|
return Collections.unmodifiableList(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MappingError> getErrors() {
|
||||||
|
return Collections.unmodifiableList(errors);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a field by its Java name, i.e. the name of the instance variable
|
* Get a field by its Java name, i.e. the name of the instance variable
|
||||||
* in the `@Entity` class
|
* in the `@Entity` class
|
||||||
@ -184,6 +191,10 @@ public class DbObjectSchema {
|
|||||||
fields.add(f);
|
fields.add(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addError(MappingError error) {
|
||||||
|
errors.add(error);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the underlying CustomJpaRepository
|
* Returns the underlying CustomJpaRepository
|
||||||
* @return
|
* @return
|
||||||
|
14
src/main/java/tech/ailef/dbadmin/external/dto/MappingError.java
vendored
Normal file
14
src/main/java/tech/ailef/dbadmin/external/dto/MappingError.java
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package tech.ailef.dbadmin.external.dto;
|
||||||
|
|
||||||
|
public class MappingError {
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public MappingError(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
38
src/main/java/tech/ailef/dbadmin/external/exceptions/UnsupportedFieldTypeException.java
vendored
Normal file
38
src/main/java/tech/ailef/dbadmin/external/exceptions/UnsupportedFieldTypeException.java
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Spring Boot Database Admin - An automatically generated CRUD admin UI for Spring Boot apps
|
||||||
|
* Copyright (C) 2023 Ailef (http://ailef.tech)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package tech.ailef.dbadmin.external.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown during the computation of pagination if the requested
|
||||||
|
* page number is not valid within the current request (e.g. it is greater
|
||||||
|
* than the maximum available page). Used internally to redirect the
|
||||||
|
* user to a default page.
|
||||||
|
*/
|
||||||
|
public class UnsupportedFieldTypeException extends DbAdminException {
|
||||||
|
private static final long serialVersionUID = -8891734807568233099L;
|
||||||
|
|
||||||
|
public UnsupportedFieldTypeException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnsupportedFieldTypeException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -59,6 +59,14 @@ tr.table-data-row td:last-child, tr.table-data-row th:last-child {
|
|||||||
width: 96px;
|
width: 96px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning-col {
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-col a .bi {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
h1 .bi {
|
h1 .bi {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
th:required="${!field.isNullable() && !field.isPrimaryKey()}"
|
th:required="${!field.isNullable() && !field.isPrimaryKey()}"
|
||||||
></input>
|
></input>
|
||||||
|
<!--
|
||||||
<th:block th:fragment="offset_datetime(field, create, name, value)">
|
<th:block th:fragment="offset_datetime(field, create, name, value)">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input placeholder="NULL"
|
<input placeholder="NULL"
|
||||||
@ -63,6 +64,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
-->
|
||||||
<input placeholder="NULL" th:fragment="date(field, create, name, value)"
|
<input placeholder="NULL" th:fragment="date(field, create, name, value)"
|
||||||
type="date"
|
type="date"
|
||||||
th:value="${value}"
|
th:value="${value}"
|
||||||
|
@ -25,12 +25,19 @@
|
|||||||
<h4 class="fw-bold" th:text="${package}"></h4>
|
<h4 class="fw-bold" th:text="${package}"></h4>
|
||||||
<table class="table table-striped mt-4" th:if="${!schemas.isEmpty()}">
|
<table class="table table-striped mt-4" th:if="${!schemas.isEmpty()}">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th></th>
|
||||||
<th>Table</th>
|
<th>Table</th>
|
||||||
<th>Rows</th>
|
<th>Rows</th>
|
||||||
<th>Java class</th>
|
<th>Java class</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr th:each="schema : ${schemas.get(package)}">
|
<tr th:each="schema : ${schemas.get(package)}">
|
||||||
|
<td class="warning-col">
|
||||||
|
<a th:if="${!schema.getErrors().isEmpty()}"
|
||||||
|
title="Some errors or warnings were raised during processing of this schema."
|
||||||
|
th:href="|/${baseUrl}/model/${schema.getClassName()}/schema|">
|
||||||
|
<i class="bi bi-exclamation-triangle"></i></a>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a th:text="${schema.getTableName()}"
|
<a th:text="${schema.getTableName()}"
|
||||||
th:href="|/${baseUrl}/model/${schema.getClassName()}|"></a>
|
th:href="|/${baseUrl}/model/${schema.getClassName()}|"></a>
|
||||||
|
@ -67,6 +67,12 @@
|
|||||||
<td th:text="${field.isNullable()}"></td>
|
<td th:text="${field.isNullable()}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<div class="separator mb-2 mt-2"></div>
|
||||||
|
<h3 th:if="${!schema.getErrors().isEmpty()}" class="fw-bold"><i class="bi bi-exclamation-triangle"></i> Errors</h3>
|
||||||
|
<ul>
|
||||||
|
<li th:each="error : ${schema.getErrors()}" th:text="${error.getMessage()}">
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user