mirror of
https://github.com/dalbodeule/snap-admin.git
synced 2025-06-08 21:38:21 +00:00
WIP
This commit is contained in:
parent
d34676f7a7
commit
82311fd23e
@ -39,19 +39,23 @@ import tech.ailef.dbadmin.misc.Utils;
|
|||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/dbadmin")
|
@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
|
* - double data source for internal database and settings
|
||||||
* - role based authorization (PRO)
|
* - role based authorization (PRO)
|
||||||
* - Pagination in one to many results?
|
* - Pagination in one to many results?
|
||||||
* - BLOB upload (WIP: check edit not working)
|
|
||||||
* - AI console (PRO)
|
* - AI console (PRO)
|
||||||
* - Action logs
|
* - Action logs
|
||||||
* - Boolean icons
|
* - Boolean icons
|
||||||
* - Boolean in create/edit is checkbox
|
* - Boolean in create/edit is checkbox
|
||||||
|
* - Documentation
|
||||||
* - SQL console (PRO)
|
* - SQL console (PRO)
|
||||||
* - JPA Validation (PRO)
|
* - JPA Validation (PRO)
|
||||||
* - Logging
|
* - Logging
|
||||||
* - Selenium tests
|
* - Selenium tests
|
||||||
* - @DisplayImage
|
|
||||||
* - Logs in web ui
|
* - Logs in web ui
|
||||||
* - Tests: AutocompleteController, REST API, create/edit
|
* - Tests: AutocompleteController, REST API, create/edit
|
||||||
*/
|
*/
|
||||||
@ -81,7 +85,6 @@ public class DefaultDbAdminController {
|
|||||||
model.addAttribute("activePage", "home");
|
model.addAttribute("activePage", "home");
|
||||||
model.addAttribute("title", "Entities | Index");
|
model.addAttribute("title", "Entities | Index");
|
||||||
|
|
||||||
|
|
||||||
return "home";
|
return "home";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,8 +275,6 @@ public class DefaultDbAdminController {
|
|||||||
@RequestParam MultiValueMap<String, String> formParams,
|
@RequestParam MultiValueMap<String, String> formParams,
|
||||||
@RequestParam Map<String, MultipartFile> files,
|
@RequestParam Map<String, MultipartFile> files,
|
||||||
RedirectAttributes attr) {
|
RedirectAttributes attr) {
|
||||||
|
|
||||||
|
|
||||||
// Extract all parameters that have exactly 1 value,
|
// Extract all parameters that have exactly 1 value,
|
||||||
// as these will be the raw values for the object that is being
|
// as these will be the raw values for the object that is being
|
||||||
// created.
|
// created.
|
||||||
|
@ -22,6 +22,7 @@ import tech.ailef.dbadmin.dbmapping.DbAdminRepository;
|
|||||||
import tech.ailef.dbadmin.dbmapping.DbFieldValue;
|
import tech.ailef.dbadmin.dbmapping.DbFieldValue;
|
||||||
import tech.ailef.dbadmin.dbmapping.DbObject;
|
import tech.ailef.dbadmin.dbmapping.DbObject;
|
||||||
import tech.ailef.dbadmin.dbmapping.DbObjectSchema;
|
import tech.ailef.dbadmin.dbmapping.DbObjectSchema;
|
||||||
|
import tech.ailef.dbadmin.exceptions.DbAdminException;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/dbadmin/download")
|
@RequestMapping("/dbadmin/download")
|
||||||
@ -65,7 +66,18 @@ public class DownloadController {
|
|||||||
|
|
||||||
if (object.isPresent()) {
|
if (object.isPresent()) {
|
||||||
DbObject dbObject = object.get();
|
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();
|
byte[] file = (byte[])dbFieldValue.getValue();
|
||||||
|
|
||||||
String filename = schema.getClassName() + "_" + id + "_" + fieldName;
|
String filename = schema.getClassName() + "_" + id + "_" + fieldName;
|
||||||
|
@ -179,8 +179,11 @@ public class DbObject {
|
|||||||
String capitalize = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
|
String capitalize = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
|
||||||
Method[] methods = instance.getClass().getDeclaredMethods();
|
Method[] methods = instance.getClass().getDeclaredMethods();
|
||||||
|
|
||||||
|
DbField dbField = schema.getFieldByJavaName(fieldName);
|
||||||
|
if (dbField == null) return null;
|
||||||
|
|
||||||
String prefix = "get";
|
String prefix = "get";
|
||||||
if (schema.getFieldByJavaName(fieldName).getType() == DbFieldType.BOOLEAN) {
|
if (dbField.getType() == DbFieldType.BOOLEAN) {
|
||||||
prefix = "is";
|
prefix = "is";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ tr.table-data-row td:last-child, tr.table-data-row th:last-child {
|
|||||||
|
|
||||||
.row-icons {
|
.row-icons {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
width: 128px;
|
width: 96px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 .bi {
|
h1 .bi {
|
||||||
@ -116,6 +116,8 @@ h1 a:hover {
|
|||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
z-index: 999;
|
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 {
|
.suggestion {
|
||||||
@ -128,7 +130,7 @@ h1 a:hover {
|
|||||||
|
|
||||||
.suggestion:hover {
|
.suggestion:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #FFF;
|
background-color: #EBF7FF;
|
||||||
border-bottom: 2px solid #ADDEFF;
|
border-bottom: 2px solid #ADDEFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
function updateBulkActions(table, selected) {
|
function updateBulkActions(table, selected) {
|
||||||
let divs = document.querySelectorAll(".bulk-actions");
|
let divs = document.querySelectorAll(".bulk-actions");
|
||||||
divs.forEach(div => {
|
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", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
let selected = 0;
|
let selected = 0;
|
||||||
|
|
||||||
if (document.getElementById('delete-form') != null) {
|
document.querySelectorAll(".delete-form").forEach(form => {
|
||||||
document.getElementById('delete-form').addEventListener('submit', function(e) {
|
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) {
|
if (selected == 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
alert('No items selected');
|
alert('No items selected');
|
||||||
|
@ -5,7 +5,15 @@
|
|||||||
<tr th:fragment="data_row(row, selectable)" class="table-data-row">
|
<tr th:fragment="data_row(row, selectable)" class="table-data-row">
|
||||||
<td th:if=${selectable} class="table-checkbox">
|
<td th:if=${selectable} class="table-checkbox">
|
||||||
<input type="checkbox" class="form-check-input" name="ids"
|
<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>
|
||||||
<td th:each="field : ${schema.getSortedFields()}"
|
<td th:each="field : ${schema.getSortedFields()}"
|
||||||
th:classAppend="${field.isBinary() ? 'text-center' : ''}">
|
th:classAppend="${field.isBinary() ? 'text-center' : ''}">
|
||||||
@ -20,15 +28,6 @@
|
|||||||
<td th:each="colName : ${schema.getComputedColumnNames()}">
|
<td th:each="colName : ${schema.getComputedColumnNames()}">
|
||||||
<span th:text="${row.compute(colName)}"></span>
|
<span th:text="${row.compute(colName)}"></span>
|
||||||
</td>
|
</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>
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<div th:if="${results != null && results.size() > 0}">
|
<div th:if="${results != null && results.size() > 0}">
|
||||||
<table class="table table-striped align-middle mt-3">
|
<table class="table table-striped align-middle mt-3">
|
||||||
<tr class="table-data-row">
|
<tr class="table-data-row">
|
||||||
|
<th class="row-icons"></th>
|
||||||
<th th:each="field : ${schema.getSortedFields()}">
|
<th th:each="field : ${schema.getSortedFields()}">
|
||||||
<div class="m-0 p-0 d-flex justify-content-between">
|
<div class="m-0 p-0 d-flex justify-content-between">
|
||||||
<div class="column-title">
|
<div class="column-title">
|
||||||
|
@ -2,18 +2,19 @@
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
|
||||||
<head></head>
|
<head></head>
|
||||||
<body>
|
<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()}">
|
<div th:if="${results.isEmpty()}">
|
||||||
<p>This table contains no data.</p>
|
<p>This table contains no data.</p>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${results.size() > 0}">
|
<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>
|
</form>
|
||||||
<nav th:replace="~{fragments/resources :: pagination(${page})}">
|
<nav th:replace="~{fragments/resources :: pagination(${page})}">
|
||||||
</nav>
|
</nav>
|
||||||
<table class="table table-striped align-middle mt-3">
|
<table class="table table-striped align-middle mt-3">
|
||||||
<tr class="table-data-row">
|
<tr class="table-data-row">
|
||||||
<th class="table-checkbox"><input type="checkbox" class="form-check-input check-all"></th>
|
<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()}">
|
<th class="table-data-row" th:each="field : ${schema.getSortedFields()}">
|
||||||
<div class="m-0 p-0 d-flex justify-content-between">
|
<div class="m-0 p-0 d-flex justify-content-between">
|
||||||
<div class="column-title">
|
<div class="column-title">
|
||||||
@ -56,7 +57,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="m-0 p-0 dbfieldtype"><small>COMPUTED</small></p>
|
<p class="m-0 p-0 dbfieldtype"><small>COMPUTED</small></p>
|
||||||
</th>
|
</th>
|
||||||
<th></th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<th:block th:each="r : ${results}">
|
<th:block th:each="r : ${results}">
|
||||||
<tr th:replace="~{fragments/data_row :: data_row(row=${r},selectable=${true})}"></tr>
|
<tr th:replace="~{fragments/data_row :: data_row(row=${r},selectable=${true})}"></tr>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user