浏览代码

Add appendixImage controllers

Andrew Grant 1 月之前
父节点
当前提交
7104243043

+ 4 - 8
src/main/java/scot/carricksoftware/grants/constants/ImageAttributeConstants.java

@@ -13,22 +13,18 @@ public class ImageAttributeConstants {
     private ImageAttributeConstants() {
         // to stop checkstyle complaining
     }
-
-    @SuppressWarnings({"unused"})
+    
     public static final String IMAGES = "images";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_COMMAND = "imageCommand";
 
     public static final String PERSON_IMAGES = "personImages";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_COMMAND = "personImageCommand";
-
-
+    
     public static final String PLACE_IMAGES = "placeImages";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_COMMAND = "placeImageCommand";
 
-
+    public static final String APPENDIX_IMAGES = "appendixImages";
+    public static final String APPENDIX_IMAGE_COMMAND = "appendixImageCommand";
 
 
 

+ 14 - 33
src/main/java/scot/carricksoftware/grants/constants/ImageMappingConstants.java

@@ -14,70 +14,51 @@ public class ImageMappingConstants {
         // to stop checkstyle complaining
     }
 
-
-    @SuppressWarnings({"unused"})
+    
     public static final String IMAGE_LIST = "/images";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_NEXT = "/images/next";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_PREVIOUS = "/images/prev";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_REWIND = "/images/rewind";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_FF = "/images/ff";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_NEW = "/image/new";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE = "/image";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_SHOW = "/image/{id}/show";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_DELETE = "/image/{id}/delete";
-    @SuppressWarnings({"unused"})
     public static final String IMAGE_EDIT = "image/{id}/edit";
-
-
-    @SuppressWarnings({"unused"})
+    
     public static final String PERSON_IMAGE_LIST = "/personImages";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_NEXT = "/personImages/next";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_PREVIOUS = "/personImages/prev";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_REWIND = "/personImages/rewind";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_FF = "/personImages/ff";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_NEW = "/personImage/new";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE = "/personImage";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_SHOW = "/personImage/{id}/show";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_DELETE = "/personImage/{id}/delete";
-    @SuppressWarnings({"unused"})
     public static final String PERSON_IMAGE_EDIT = "personImage/{id}/edit";
-
+    
     public static final String PLACE_IMAGE_LIST = "/placeImages";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_NEXT = "/placeImages/next";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_PREVIOUS = "/placeImages/prev";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_REWIND = "/placeImages/rewind";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_FF = "/placeImages/ff";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_NEW = "/placeImage/new";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE = "/placeImage";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_SHOW = "/placeImage/{id}/show";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_DELETE = "/placeImage/{id}/delete";
-    @SuppressWarnings({"unused"})
     public static final String PLACE_IMAGE_EDIT = "placeImage/{id}/edit";
 
+
+    public static final String APPENDIX_IMAGE_LIST = "/appendixImages";
+    public static final String APPENDIX_IMAGE_NEXT = "/appendixImages/next";
+    public static final String APPENDIX_IMAGE_PREVIOUS = "/appendixImages/prev";
+    public static final String APPENDIX_IMAGE_REWIND = "/appendixImages/rewind";
+    public static final String APPENDIX_IMAGE_FF = "/appendixImages/ff";
+    public static final String APPENDIX_IMAGE_NEW = "/appendixImage/new";
+    public static final String APPENDIX_IMAGE = "/appendixImage";
+    public static final String APPENDIX_IMAGE_SHOW = "/appendixImage/{id}/show";
+    public static final String APPENDIX_IMAGE_DELETE = "/appendixImage/{id}/delete";
+    public static final String APPENDIX_IMAGE_EDIT = "appendixImage/{id}/edit";
 }
 
 

+ 4 - 2
src/main/java/scot/carricksoftware/grants/constants/ViewConstants.java

@@ -39,8 +39,7 @@ public class ViewConstants {
     public static final String CENSUS_ENTRY_FORM = "censusEntry/form";
 
     public static final String SELECTED_CENSUS_LIST = "selectedCensus/list";
-
-    @SuppressWarnings("unused")
+    
     public static final String BIRTH_CERTIFICATE_LIST = "certificates/birthCertificate/list";
     public static final String BIRTH_CERTIFICATE_FORM = "certificates/birthCertificate/form";
 
@@ -62,6 +61,9 @@ public class ViewConstants {
     public static final String PLACE_IMAGE_LIST = "images/placeImage/list";
     public static final String PLACE_IMAGE_FORM = "images/placeImage/form";
 
+    public static final String APPENDIX_IMAGE_LIST = "images/appendixImage/list";
+    public static final String APPENDIX_IMAGE_FORM = "images/appendixImage/form";
+
     public static final String DOCUMENT_TEXT_LIST = "text/documentText/list";
     public static final String DOCUMENT_TEXT_FORM = "text/documentText/form";
 

+ 18 - 0
src/main/java/scot/carricksoftware/grants/controllers/images/appendixImages/AppendixImageFormController.java

@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) Andrew Grant of Carrick Software 29/03/2025, 13:08. All rights reserved.
+ *
+ */
+
+package scot.carricksoftware.grants.controllers.images.appendixImages;
+
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import scot.carricksoftware.grants.commands.images.AppendixImageCommand;
+
+@SuppressWarnings("unused")
+
+public interface AppendixImageFormController {
+
+    String saveOrUpdate(@ModelAttribute AppendixImageCommand appendixImageCommand, BindingResult bindingResult, Model model);
+}

+ 111 - 0
src/main/java/scot/carricksoftware/grants/controllers/images/appendixImages/AppendixImageFormControllerImpl.java

@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) Andrew Grant of Carrick Software 29/03/2025, 13:08. All rights reserved.
+ *
+ */
+
+package scot.carricksoftware.grants.controllers.images.appendixImages;
+
+import jakarta.validation.Valid;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import scot.carricksoftware.grants.capitalisation.images.appendiximage.CapitaliseAppendixImageCommand;
+import scot.carricksoftware.grants.commands.images.AppendixImageCommand;
+import scot.carricksoftware.grants.commands.images.AppendixImageCommandImpl;
+import scot.carricksoftware.grants.constants.AttributeConstants;
+import scot.carricksoftware.grants.constants.ImageAttributeConstants;
+import scot.carricksoftware.grants.constants.ImageMappingConstants;
+import scot.carricksoftware.grants.constants.MappingConstants;
+import scot.carricksoftware.grants.constants.ViewConstants;
+import scot.carricksoftware.grants.converters.images.appendiximage.AppendixImageCommandConverterImpl;
+import scot.carricksoftware.grants.converters.images.appendiximage.AppendixImageConverterImpl;
+import scot.carricksoftware.grants.services.images.appendiximage.AppendixImageService;
+import scot.carricksoftware.grants.services.images.image.ImageService;
+import scot.carricksoftware.grants.validators.images.AppendixImageCommandValidatorImpl;
+
+
+@SuppressWarnings("LoggingSimilarMessage")
+@Controller
+public class AppendixImageFormControllerImpl implements AppendixImageFormController {
+
+    private static final Logger logger = LogManager.getLogger(AppendixImageFormControllerImpl.class);
+    private final AppendixImageService appendixImageService;
+    @SuppressWarnings({"FieldCanBeLocal", "unused"})
+    private final AppendixImageCommandConverterImpl appendixImageCommandConverter;
+    private final AppendixImageConverterImpl appendixImageConverter;
+    private final AppendixImageCommandValidatorImpl appendixImageCommandValidatorImpl;
+    private final ImageService imageService;
+    private final CapitaliseAppendixImageCommand capitaliseAppendixImageCommand;
+
+
+    public AppendixImageFormControllerImpl(AppendixImageService appendixImageService,
+                                           AppendixImageCommandConverterImpl appendixImageCommandConverter,
+                                           AppendixImageConverterImpl appendixImageConverter,
+                                           AppendixImageCommandValidatorImpl appendixImageCommandValidatorImpl,
+                                           ImageService imageService,
+                                           CapitaliseAppendixImageCommand capitaliseAppendixImageCommand) {
+
+        this.appendixImageService = appendixImageService;
+        this.appendixImageCommandConverter = appendixImageCommandConverter;
+        this.appendixImageConverter = appendixImageConverter;
+        this.appendixImageCommandValidatorImpl = appendixImageCommandValidatorImpl;
+        this.imageService = imageService;
+        this.capitaliseAppendixImageCommand = capitaliseAppendixImageCommand;
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_NEW)
+    public final String getNewAppendixImage(final Model model) {
+        logger.debug("AppendixImageFormControllerImpl::getNewAppendixImage");
+        model.addAttribute(ImageAttributeConstants.APPENDIX_IMAGE_COMMAND, new AppendixImageCommandImpl());
+        model.addAttribute(AttributeConstants.IMAGES, imageService.findAll());
+        return ViewConstants.APPENDIX_IMAGE_FORM;
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_EDIT)
+    public final String appendixImageEdit(@Valid @PathVariable final String id, Model model) {
+        logger.debug("AppendixImageFormControllerImpl::appendixImageEdit");
+        model.addAttribute(ImageAttributeConstants.APPENDIX_IMAGE_COMMAND, appendixImageService.findById(Long.valueOf(id)));
+        model.addAttribute(AttributeConstants.IMAGES, imageService.findAll());
+        return ViewConstants.APPENDIX_IMAGE_FORM;
+    }
+
+    @Override
+    @PostMapping(ImageMappingConstants.APPENDIX_IMAGE)
+    public String saveOrUpdate(@Valid @ModelAttribute AppendixImageCommand appendixImageCommand, BindingResult bindingResult, Model model) {
+        logger.debug("AppendixImageFormControllerImpl::saveOrUpdate");
+
+        capitaliseAppendixImageCommand.capitalise(appendixImageCommand);
+        appendixImageCommandValidatorImpl.validate(appendixImageCommand, bindingResult);
+
+        if (bindingResult.hasErrors()) {
+            bindingResult.getAllErrors().forEach(error -> logger.debug(error.getDefaultMessage()));
+            model.addAttribute(AttributeConstants.IMAGES, imageService.findAll());
+            return ViewConstants.APPENDIX_IMAGE_FORM;
+        }
+
+        AppendixImageCommand savedCommand = appendixImageService.saveAppendixImageCommand(appendixImageCommand);
+        model.addAttribute(ImageAttributeConstants.APPENDIX_IMAGE_COMMAND, savedCommand);
+        model.addAttribute(AttributeConstants.IMAGES, imageService.findAll());
+        return MappingConstants.REDIRECT + ImageMappingConstants.APPENDIX_IMAGE_SHOW.replace("{id}", "" + savedCommand.getId());
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_SHOW)
+    public String showById(@PathVariable String id, Model model) {
+        logger.debug("AppendixImageFormControllerImpl::saveOrUpdate");
+        AppendixImageCommand savedCommand = appendixImageConverter.convert(appendixImageService.findById(Long.valueOf(id)));
+        model.addAttribute(ImageAttributeConstants.APPENDIX_IMAGE_COMMAND, savedCommand);
+        model.addAttribute(AttributeConstants.IMAGES, imageService.findAll());
+        return ViewConstants.APPENDIX_IMAGE_FORM;
+    }
+
+
+}

+ 29 - 0
src/main/java/scot/carricksoftware/grants/controllers/images/appendixImages/AppendixImageListController.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) Andrew Grant of Carrick Software 29/03/2025, 13:08. All rights reserved.
+ *
+ */
+
+package scot.carricksoftware.grants.controllers.images.appendixImages;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.PathVariable;
+
+@SuppressWarnings("unused")
+@Controller
+public interface AppendixImageListController {
+
+    String getListPage(final Model model);
+
+    String getNextPage(final Model model);
+
+    String getPreviousPage(final Model model);
+
+    String getFirstPage(final Model model);
+
+    String getLastPage(final Model model);
+
+    String appendixImageDelete(@PathVariable String id);
+
+    int getPageNumber();
+}

+ 108 - 0
src/main/java/scot/carricksoftware/grants/controllers/images/appendixImages/AppendixImageListControllerImpl.java

@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) Andrew Grant of Carrick Software 29/03/2025, 13:08. All rights reserved.
+ *
+ */
+
+package scot.carricksoftware.grants.controllers.images.appendixImages;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import scot.carricksoftware.grants.constants.ApplicationConstants;
+import scot.carricksoftware.grants.constants.ImageAttributeConstants;
+import scot.carricksoftware.grants.constants.ImageMappingConstants;
+import scot.carricksoftware.grants.constants.MappingConstants;
+import scot.carricksoftware.grants.constants.ViewConstants;
+import scot.carricksoftware.grants.controllers.ControllerHelper;
+import scot.carricksoftware.grants.services.images.appendiximage.AppendixImageService;
+
+import static java.lang.Integer.max;
+
+@Controller
+public class AppendixImageListControllerImpl implements AppendixImageListController {
+
+    private static final Logger logger = LogManager.getLogger(AppendixImageListControllerImpl.class);
+
+
+    private int currentPage = 0;
+    private final ControllerHelper controllerHelper;
+    private final AppendixImageService appendixImageService;
+
+    public AppendixImageListControllerImpl(ControllerHelper controllerHelper,
+                                           AppendixImageService appendixImageService) {
+        this.controllerHelper = controllerHelper;
+        this.appendixImageService = appendixImageService;
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_LIST)
+    @Override
+    public final String getListPage(final Model model) {
+        logger.debug("PersonListControllerImpl::getPersonImagePage");
+        currentPage = 0;
+        return sendAttributesAndReturn(model);
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    private String sendAttributesAndReturn(Model model) {
+        model.addAttribute(ImageAttributeConstants.APPENDIX_IMAGES, appendixImageService.getPagedAppendixImages(currentPage));
+        controllerHelper.addAttributes(model);
+        return ViewConstants.APPENDIX_IMAGE_LIST;
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_NEXT)
+    @Override
+    public final String getNextPage(final Model model) {
+        logger.debug("AppendixImageListControllerImpl::getNextPage");
+        currentPage++;
+        return sendAttributesAndReturn(model);
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_PREVIOUS)
+    @Override
+    public final String getPreviousPage(final Model model) {
+        logger.debug("AppendixImageListControllerImpl::getPreviousPage");
+        currentPage = max(0, currentPage - 1);
+        return sendAttributesAndReturn(model);
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_REWIND)
+    public final String getFirstPage(final Model model) {
+        logger.debug("AppendixImageListControllerImpl::getFirstPage");
+        currentPage = 0;
+        return sendAttributesAndReturn(model);
+    }
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_FF)
+    @Override
+    public final String getLastPage(final Model model) {
+        logger.debug("AppendixImageListControllerImpl::getLastPage");
+        long personImageCount = appendixImageService.count();
+        currentPage = (int) (personImageCount / ApplicationConstants.DEFAULT_PAGE_SIZE);
+        return sendAttributesAndReturn(model);
+    }
+
+
+    @SuppressWarnings("SameReturnValue")
+    @GetMapping(ImageMappingConstants.APPENDIX_IMAGE_DELETE)
+    @Override
+    public final String appendixImageDelete(@PathVariable final String id) {
+        logger.debug("AppendixImageListControllerImpl::personImageDelete");
+        appendixImageService.deleteById(Long.valueOf(id));
+        return MappingConstants.REDIRECT + ImageMappingConstants.APPENDIX_IMAGE_LIST;
+    }
+
+    @Override
+    public int getPageNumber() {
+        return currentPage;
+    }
+
+
+}

+ 139 - 0
src/main/resources/templates/images/appendixImage/form.html

@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<!--suppress XmlHighlighting -->
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <!-- Required meta tags -->
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- Bootstrap CSS -->
+    <!--suppress SpellCheckingInspection -->
+    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
+          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
+
+    <!--suppress SpellCheckingInspection -->
+    <script src="https://code.jquery.com/jquery-3.6.0.min.js"
+            integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
+    <title>Grants - appendix images</title>
+
+</head>
+<body>
+<!--/*@thymesVar id="appendixImageCommand" type="scot.carricksoftware.grants.commands.images.AppendixImageCommand"*/-->
+<div th:insert="~{fragments/layout::banner}"></div>
+
+<div class="container border border-info rounded-3 text-center p-4">
+    <h3>Appendix Image Details</h3>
+    <form th:object="${appendixImageCommand}" th:action="@{/appendixImage}" method="post">
+        <div th:if="${#fields.hasErrors('*')}" class="alert alert-danger">
+            <p>Please Correct The Errors Below</p>
+        </div>
+        <table style="width:100%;">
+            <tr>
+                <td style="text-align: right;">
+                    <label for="id"><span style="color: rgb(255,0,0);">*</span>Database Id :&nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <input class="form-control" id="id"
+                           th:field="*{id}" type="text" readonly>
+                </td>
+            </tr>
+            <tr>
+                <td style="text-align: right;">
+                    <label for="image">Image : &nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <select id="image" name="image" th:field="*{image}">
+                        <option th:value="${''}" th:text="${''}"></option>
+                        <option th:each="image : ${images}"
+                                th:value="${image.id}" th:text="${image.name}"></option>
+                    </select>
+                    <div th:if="${#fields.hasErrors('image')}">
+                        <ul class="text-danger">
+                            <li th:each="err : ${#fields.errors('image')}" th:text="${err}"/>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+            <tr>
+                <td style="text-align: right;">
+                    <label for="order">Order :&nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <input class="form-control" id="order"
+                           th:field="*{order}" type="text">
+                    <div th:if="${#fields.hasErrors('order')}">
+                        <ul class="text-danger">
+                            <li th:each="err : ${#fields.errors('order')}" th:text="${err}"/>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+            <tr>
+                <td style="text-align: right;">
+                    <label for="level">Level :&nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <input class="form-control" id="level"
+                           th:field="*{level}" type="text">
+                    <div th:if="${#fields.hasErrors('level')}">
+                        <ul class="text-danger">
+                            <li th:each="err : ${#fields.errors('level')}" th:text="${err}"/>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+            <tr>
+                <td style="text-align: right;">
+                    <label for="caption">Caption :&nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <input class="form-control" id="caption"
+                           th:field="*{caption}" type="text">
+                    <div th:if="${#fields.hasErrors('caption')}">
+                        <ul class="text-danger">
+                            <li th:each="err : ${#fields.errors('caption')}" th:text="${err}"/>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+
+            <tr>
+                <td style="text-align: right;">
+                    <label for="width">Width :&nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <input class="form-control" id="width"
+                           th:field="*{width}" type="text">
+                    <div th:if="${#fields.hasErrors('width')}">
+                        <ul class="text-danger">
+                            <li th:each="err : ${#fields.errors('width')}" th:text="${err}"/>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+            <tr>
+                <td style="text-align: right;">
+                    <label for="height">Height :&nbsp;</label>
+                </td>
+                <td style="text-align: left;">
+                    <input class="form-control" id="height"
+                           th:field="*{height}" type="text">
+                    <div th:if="${#fields.hasErrors('height')}">
+                        <ul class="text-danger">
+                            <li th:each="err : ${#fields.errors('height')}" th:text="${err}"/>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+            <tr>
+                <td>&nbsp;</td>
+            </tr>
+        </table>
+        <button type="submit" class="btn btn-primary">Commit</button>
+        <a class="btn btn-secondary" th:href="@{/personImages}" th:text="${'List all'}">List all</a>
+        <a class="btn btn-success" th:href="@{/}" th:text="${'Home'}">Home</a>
+        <h6><span style="color: rgb(255,0,0);">*</span><span> Cannot be edited</span></h6>
+    </form>
+</div>
+</body>
+</html>

+ 77 - 0
src/main/resources/templates/images/appendixImage/list.html

@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+
+<!--
+  ~ Copyright (c) 2025 Andrew Grant of Carrick Software .
+  ~ All rights reserved.
+  -->
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8"/>
+    <title>People </title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
+</head>
+<body>
+<div th:insert="~{fragments/layout::banner}"></div>
+
+<div class="container text-center">
+    <div class="container border border-info
+                    rounded-3 text-center p-4">
+        <h3> Appendix Images</h3>
+        <table class="table table-striped table-bordered">
+            <thead class="table-dark">
+            <tr>
+                <th>ID</th>
+                <th>Order</th>
+                <th>Level</th>
+                <th>Caption</th>
+                <th></th>
+                <th></th>
+            </tr>
+            </thead>
+
+            <tr th:each="image : ${appendixImages}">
+                <!--/*@thymesVar id="person" type="scot.carricksoftware.grants.domains.people.Person"*/-->
+                <td th:text="${image.id}">123</td>
+                <td th:text="${image.order}"></td>
+                <td th:text="${image.level}"></td>
+                <td th:text="${image.caption}"></td>
+                <td>
+                    <div th:if="${image.image != null and !#strings.isEmpty(image.image)}">
+                        <img class='img-thumbnail' th:src="'data:image/jpeg;base64,' + ${image.image.imageData} "
+                             width="50" height="50" alt=""/>
+                    </div>
+                </td>
+                <td><span>
+                        <a th:action="delete" class="btn btn-danger btn-sm" href=""
+                           th:href="@{'personImage/' + ${image.id} + '/delete'}"
+                           th:text="Delete"></a>
+                    <a th:action="edit" class="btn btn-warning btn-sm"
+                       th:href="@{'personImage/' + ${image.id} + '/edit'}"
+                       th:text="Edit"></a>
+                    </span></td>
+            </tr>
+            <tfoot>
+            <tr>
+                <td colspan="4"><span>
+                        <a th:action="rewind" class="btn btn-secondary btn-sm" th:href="@{/personImages/rewind}"
+                           th:text="'<<'"></a>
+                         <a th:action="back" class="btn btn-secondary btn-sm"
+                            th:href="@{/personImages/prev}" th:text="'<'"></a>
+                         <a th:action="new" class="btn btn-primary btn-sm" th:href="@{/personImage/new}"
+                            th:text="'New Person Image'"></a>
+                         <a th:action="home" class="btn btn-success btn-sm"
+                            th:href="@{/}" th:text="'Home'"></a>
+                         <a th:action="forward" class="btn btn-secondary btn-sm"
+                            th:href="@{/personImages/next}" th:text="'>'"></a>
+                         <a th:action="end" class="btn btn-secondary btn-sm" th:href="@{/personImages/ff}"
+                            th:text="'>>'"></a>
+                        </span></td>
+            </tr>
+            </tfoot>
+        </table>
+    </div>
+</div>
+</body>
+</html>
+