diff --git a/src/main/java/tech/ailef/dbadmin/external/annotations/ReadOnly.java b/src/main/java/tech/ailef/dbadmin/external/annotations/ReadOnly.java
new file mode 100644
index 0000000..b7201fc
--- /dev/null
+++ b/src/main/java/tech/ailef/dbadmin/external/annotations/ReadOnly.java
@@ -0,0 +1,35 @@
+/*
+ * 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 .
+ */
+
+
+package tech.ailef.dbadmin.external.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a field as read-only. The field can be filled at creation time, but
+ * it will be shown as disabled during edits, making it impossible to change its
+ * value after creation.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ReadOnly {
+}
\ No newline at end of file
diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java
index e3deae7..ddd0e52 100644
--- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java
+++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/CustomJpaRepository.java
@@ -110,6 +110,7 @@ public class CustomJpaRepository extends SimpleJpaRepository {
for (DbField field : schema.getSortedFields()) {
if (field.isPrimaryKey()) continue;
+ if (field.isReadOnly()) continue;
boolean keepValue = params.getOrDefault("__keep_" + field.getName(), "off").equals("on");
if (keepValue) continue;
diff --git a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java
index 4b12fdc..62a875c 100644
--- a/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java
+++ b/src/main/java/tech/ailef/dbadmin/external/dbmapping/DbField.java
@@ -30,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import tech.ailef.dbadmin.external.annotations.DisplayImage;
import tech.ailef.dbadmin.external.annotations.Filterable;
import tech.ailef.dbadmin.external.annotations.FilterableType;
+import tech.ailef.dbadmin.external.annotations.ReadOnly;
/**
* Represent a field on the database, generated from an Entity class instance variable.
@@ -190,6 +191,10 @@ public class DbField {
return filterable != null && filterable.type() == FilterableType.CATEGORICAL;
}
+ public boolean isReadOnly() {
+ return getPrimitiveField().getAnnotation(ReadOnly.class) != null;
+ }
+
public Set getAllValues() {
List> findAll = schema.getJpaRepository().findAll();
return findAll.stream()
diff --git a/src/main/resources/templates/model/create.html b/src/main/resources/templates/model/create.html
index 0878c85..693af38 100644
--- a/src/main/resources/templates/model/create.html
+++ b/src/main/resources/templates/model/create.html
@@ -56,6 +56,7 @@
class="form-control" th:id="|__id_${field.getName()}|"
th:required="${!field.isNullable() && !field.isPrimaryKey()}"
rows="5"
+ th:classAppend="${field.isReadOnly() && !create ? 'disable' : ''}"
>
@@ -65,7 +66,8 @@
${create ? (params != null ? params.getOrDefault(field.getName(), '') : '')
: (object != null ? object.get(field).getValue() : '' )}
"
- class="form-control" th:id="|__id_${field.getName()}|"
+ th:class="|form-control ${field.isReadOnly() && !create ? 'disable' : ''}|"
+ th:id="|__id_${field.getName()}|"
th:classAppend="${field.isPrimaryKey() && object != null ? 'disable' : ''}"
th:required="${!field.isNullable() && !field.isPrimaryKey()}"
step="any"
@@ -81,17 +83,21 @@
th:data-fieldname="${field.getName()}"
th:id="|__keep_${field.getName()}|"
checked
+ th:classAppend="${field.isReadOnly() && !create ? 'disable' : ''}"
th:name="|__keep_${field.getName()}|">
Keep current data