This commit is contained in:
Francesco 2023-09-20 20:18:56 +02:00
parent d34676f7a7
commit 82311fd23e
8 changed files with 51 additions and 25 deletions

View File

@ -39,19 +39,23 @@ import tech.ailef.dbadmin.misc.Utils;
@Controller
@RequestMapping("/dbadmin")
/**
* FOR 0.0.3:
* @DisplayImage DONE TODO: write docs in README
* Fixed/improved edit page for binary fields (files) DONE
*
* TODO
* - double data source for internal database and settings
* - role based authorization (PRO)
* - Pagination in one to many results?
* - BLOB upload (WIP: check edit not working)
* - AI console (PRO)
* - Action logs
* - Boolean icons
* - Boolean in create/edit is checkbox
* - Documentation
* - SQL console (PRO)
* - JPA Validation (PRO)
* - Logging
* - Selenium tests
* - @DisplayImage
* - Logs in web ui
* - Tests: AutocompleteController, REST API, create/edit
*/
@ -81,7 +85,6 @@ public class DefaultDbAdminController {
model.addAttribute("activePage", "home");
model.addAttribute("title", "Entities | Index");
return "home";
}
@ -272,8 +275,6 @@ public class DefaultDbAdminController {
@RequestParam MultiValueMap<String, String> formParams,
@RequestParam Map<String, MultipartFile> files,
RedirectAttributes attr) {
// Extract all parameters that have exactly 1 value,
// as these will be the raw values for the object that is being
// created.

View File

@ -22,6 +22,7 @@ import tech.ailef.dbadmin.dbmapping.DbAdminRepository;
import tech.ailef.dbadmin.dbmapping.DbFieldValue;
import tech.ailef.dbadmin.dbmapping.DbObject;
import tech.ailef.dbadmin.dbmapping.DbObjectSchema;
import tech.ailef.dbadmin.exceptions.DbAdminException;
@Controller
@RequestMapping("/dbadmin/download")
@ -65,7 +66,18 @@ public class DownloadController {
if (object.isPresent()) {
DbObject dbObject = object.get();
DbFieldValue dbFieldValue = dbObject.get(fieldName);
DbFieldValue dbFieldValue;
try {
dbFieldValue = dbObject.get(fieldName);
} catch (DbAdminException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Field not found", e);
}
if (dbFieldValue.getValue() == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "There's no file attached to this item");
}
byte[] file = (byte[])dbFieldValue.getValue();
String filename = schema.getClassName() + "_" + id + "_" + fieldName;

View File

@ -179,8 +179,11 @@ public class DbObject {
String capitalize = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
Method[] methods = instance.getClass().getDeclaredMethods();
DbField dbField = schema.getFieldByJavaName(fieldName);
if (dbField == null) return null;
String prefix = "get";
if (schema.getFieldByJavaName(fieldName).getType() == DbFieldType.BOOLEAN) {
if (dbField.getType() == DbFieldType.BOOLEAN) {
prefix = "is";
}

View File

@ -56,7 +56,7 @@ tr.table-data-row td:last-child, tr.table-data-row th:last-child {
.row-icons {
font-size: 1.2rem;
width: 128px;
width: 96px;
}
h1 .bi {
@ -116,6 +116,8 @@ h1 a:hover {
max-height: 300px;
overflow: auto;
z-index: 999;
-webkit-box-shadow: 0px 11px 12px -1px rgba(0,0,0,0.13);
box-shadow: 0px 11px 12px -1px rgba(0,0,0,0.13);
}
.suggestion {
@ -128,7 +130,7 @@ h1 a:hover {
.suggestion:hover {
cursor: pointer;
background-color: #FFF;
background-color: #EBF7FF;
border-bottom: 2px solid #ADDEFF;
}

View File

@ -1,15 +1,23 @@
function updateBulkActions(table, selected) {
let divs = document.querySelectorAll(".bulk-actions");
divs.forEach(div => {
div.innerHTML = `${selected} items selected <input type="submit" form="delete-form" class="ui-btn btn btn-secondary" value="Delete">`;
div.innerHTML = `${selected} items selected <input type="submit" form="multi-delete-form" class="ui-btn btn btn-secondary" value="Delete">`;
});
}
document.addEventListener("DOMContentLoaded", () => {
let selected = 0;
if (document.getElementById('delete-form') != null) {
document.getElementById('delete-form').addEventListener('submit', function(e) {
document.querySelectorAll(".delete-form").forEach(form => {
form.addEventListener('submit', function(e) {
if (!confirm('Are you sure you want to delete this item?')) {
e.preventDefault();
}
});
});
if (document.getElementById('multi-delete-form') != null) {
document.getElementById('multi-delete-form').addEventListener('submit', function(e) {
if (selected == 0) {
e.preventDefault();
alert('No items selected');

View File

@ -5,7 +5,15 @@
<tr th:fragment="data_row(row, selectable)" class="table-data-row">
<td th:if=${selectable} class="table-checkbox">
<input type="checkbox" class="form-check-input" name="ids"
th:value="${row.getPrimaryKeyValue()}" form="delete-form">
th:value="${row.getPrimaryKeyValue()}" form="multi-delete-form">
</td>
<td class="text-center row-icons">
<a class="ps-1" th:href="|/dbadmin/model/${schema.getJavaClass().getName()}/edit/${row.getPrimaryKeyValue()}|">
<i class="bi bi-pencil-square"></i></a>
<form class="delete-form" method="POST"
th:action="|/dbadmin/model/${schema.getJavaClass().getName()}/delete/${row.getPrimaryKeyValue()}|">
<button><i class="bi bi-trash"></i></button>
</form>
</td>
<td th:each="field : ${schema.getSortedFields()}"
th:classAppend="${field.isBinary() ? 'text-center' : ''}">
@ -20,15 +28,6 @@
<td th:each="colName : ${schema.getComputedColumnNames()}">
<span th:text="${row.compute(colName)}"></span>
</td>
<td class="text-center row-icons" th:if="${selectable}">
<a class="ps-1" th:href="|/dbadmin/model/${schema.getJavaClass().getName()}/edit/${row.getPrimaryKeyValue()}|">
<i class="bi bi-pencil-square"></i></a>
<form class="delete-form" method="POST"
th:action="|/dbadmin/model/${schema.getJavaClass().getName()}/delete/${row.getPrimaryKeyValue()}|">
<button><i class="bi bi-trash"></i></button>
</form>
</td>
</tr>

View File

@ -9,6 +9,7 @@
<div th:if="${results != null && results.size() > 0}">
<table class="table table-striped align-middle mt-3">
<tr class="table-data-row">
<th class="row-icons"></th>
<th th:each="field : ${schema.getSortedFields()}">
<div class="m-0 p-0 d-flex justify-content-between">
<div class="column-title">

View File

@ -2,18 +2,19 @@
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head></head>
<body>
<div class="table-selectable" th:fragment="table(results, schema)">
<div class="table-selectable table-responsive" th:fragment="table(results, schema)">
<div th:if="${results.isEmpty()}">
<p>This table contains no data.</p>
</div>
<div th:if="${results.size() > 0}">
<form id="delete-form" th:action="|/dbadmin/model/${schema.getClassName()}/delete|" method="POST">
<form id="multi-delete-form" th:action="|/dbadmin/model/${schema.getClassName()}/delete|" method="POST">
</form>
<nav th:replace="~{fragments/resources :: pagination(${page})}">
</nav>
<table class="table table-striped align-middle mt-3">
<tr class="table-data-row">
<th class="table-checkbox"><input type="checkbox" class="form-check-input check-all"></th>
<th></th>
<th class="table-data-row" th:each="field : ${schema.getSortedFields()}">
<div class="m-0 p-0 d-flex justify-content-between">
<div class="column-title">
@ -56,7 +57,6 @@
</div>
<p class="m-0 p-0 dbfieldtype"><small>COMPUTED</small></p>
</th>
<th></th>
</tr>
<th:block th:each="r : ${results}">
<tr th:replace="~{fragments/data_row :: data_row(row=${r},selectable=${true})}"></tr>