Switched to bootstrap v.4, added datepicker & enhanced autocomplete.

This commit is contained in:
Alexey Zinchenko 2019-05-09 20:55:39 +03:00
parent 0c2f38ef7a
commit fab69122bb
15 changed files with 189 additions and 147 deletions

14
pom.xml
View File

@ -68,18 +68,28 @@
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.4.0</version>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap-datetimepicker</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jQuery-Autocomplete</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
<version>5.8.1</version>
</dependency>
</dependencies>
<build>

View File

@ -14,9 +14,9 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.SmartValidator;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.Optional;
@Controller
@ -26,17 +26,18 @@ public class OrderController {
private OrderService orderService;
private ClientService clientService;
private MechanicService mechanicService;
private SmartValidator smartValidator;
public OrderController(OrderService orderService, ClientService clientService, MechanicService mechanicService) {
public OrderController(OrderService orderService, ClientService clientService, MechanicService mechanicService, SmartValidator smartValidator) {
this.orderService = orderService;
this.clientService = clientService;
this.mechanicService = mechanicService;
this.smartValidator = smartValidator;
}
@GetMapping
public String index(@PageableDefault Pageable pageable, @RequestParam(required = false) String client, @RequestParam(required = false) String description,
@RequestParam(required = false) OrderStatus orderStatus, ModelMap modelMap) {
Page<Order> orderList = orderService.findAll(OrderSpecifications.search(client, description, orderStatus), pageable);
modelMap.addAttribute("orderList", orderList.getContent());
@ -61,8 +62,6 @@ public class OrderController {
Optional<Order> orderOptional = orderService.findById(id);
if (orderOptional.isPresent()) {
model.addAttribute("order", orderOptional.get());
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", OrderStatus.values());
return "order/edit";
} else {
@ -72,11 +71,16 @@ public class OrderController {
}
@PostMapping(value = "/update/{id}")
public String update(@Valid Order order, BindingResult bindingResult, @PathVariable long id, Model model) {
public String update(Order order, BindingResult bindingResult, @PathVariable long id, Long clientId, Long mechanicId, Model model) {
if (clientId != null) {
clientService.findById(clientId).ifPresent(order::setClient);
}
if (mechanicId != null) {
mechanicService.findById(mechanicId).ifPresent(order::setMechanic);
}
smartValidator.validate(order, bindingResult);
if (bindingResult.hasErrors()) {
order.setId(id); // why should we do this?
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", OrderStatus.values());
return "order/edit";
}
@ -86,10 +90,15 @@ public class OrderController {
}
@PostMapping(value = "/create")
public String save(@Valid Order order, BindingResult bindingResult, Model model) {
public String save(Order order, BindingResult bindingResult, Long clientId, Long mechanicId, Model model) {
if (clientId != null) {
clientService.findById(clientId).ifPresent(order::setClient);
}
if (mechanicId != null) {
mechanicService.findById(mechanicId).ifPresent(order::setMechanic);
}
smartValidator.validate(order, bindingResult);
if (bindingResult.hasErrors()) {
model.addAttribute("clientIdsList", clientService.getAllClientIds());
model.addAttribute("mechanicIdsList", mechanicService.getAllMechanicIds());
model.addAttribute("orderStatuses", OrderStatus.values());
return "order/edit";
}

View File

@ -16,16 +16,18 @@ public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private Long id;
@NotNull
@Size(max = 1024)
private String description;
@NotNull
@ManyToOne(fetch = FetchType.EAGER) // change to LAZY after DTO implementation
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@NotNull
@ManyToOne(fetch = FetchType.EAGER) // change to LAZY after DTO implementation
@JoinColumn(name = "mechanic_id", nullable = false)
private Mechanic mechanic;
@ -58,11 +60,11 @@ public class Order {
public Order() {
}
public long getId() {
public Long getId() {
return id;
}
public void setId(long id) {
public void setId(Long id) {
this.id = id;
}

View File

@ -10,7 +10,7 @@ abstract public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected long id;
protected Long id;
@NotNull
@Size(max = 64)

View File

@ -1,18 +1,7 @@
body {
}
.fieldError {
border: 1px solid red;
}
.word-breakable {
word-break: break-all;
}
.btn-group {
display: flex;
}
.autocomplete-suggestions { border: 1px solid #999; background: #FFF; overflow: auto; }
.autocomplete-suggestion { padding: 2px 5px; white-space: nowrap; overflow: hidden; }
.autocomplete-selected { background: #F0F0F0; }

View File

@ -5,41 +5,42 @@
<title th:text="#{default.title}"></title>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{client.title}"></h1>
</div>
<div layout:fragment="content">
<form th:action="'/client/' + ${client.id != null ? 'update/' + client.id : 'create'}" th:object="${client}" method="post">
<div class="form-group row">
<label for="clientFirstName" class="col-sm-2 col-form-label" th:text="#{firstName.label}"></label>
<div class="col-sm-10">
<input type="text" name="firstName" class="form-control" id="clientFirstName" th:field="*{firstName}" th:errorclass="fieldError" th:value="${client.firstName}">
<input type="text" name="firstName" class="form-control" id="clientFirstName" th:field="*{firstName}" th:errorclass="is-invalid" th:value="${client.firstName}">
<div th:replace="common::errors('firstName')"></div>
</div>
</div>
<div class="form-group row">
<label for="clientMiddleName" class="col-sm-2 col-form-label" th:text="#{middleName.label}"></label>
<div class="col-sm-10">
<input type="text" name="middleName" class="form-control" id="clientMiddleName" th:field="*{middleName}" th:errorclass="fieldError" th:value="${client.middleName}">
<input type="text" name="middleName" class="form-control" id="clientMiddleName" th:field="*{middleName}" th:errorclass="is-invalid" th:value="${client.middleName}">
<div th:replace="common::errors('middleName')"></div>
</div>
</div>
<div class="form-group row">
<label for="clientLastName" class="col-sm-2 col-form-label" th:text="#{lastName.label}"></label>
<div class="col-sm-10">
<input type="text" name="lastName" class="form-control" id="clientLastName" th:field="*{lastName}" th:errorclass="fieldError" th:value="${client.lastName}">
<input type="text" name="lastName" class="form-control" id="clientLastName" th:field="*{lastName}" th:errorclass="is-invalid" th:value="${client.lastName}">
<div th:replace="common::errors('lastName')"></div>
</div>
</div>
<div class="form-group row">
<label for="clientPhoneNo" class="col-sm-2 col-form-label" th:text="#{phoneNo.label}"></label>
<div class="col-sm-10">
<input type="text" name="phoneNo" class="form-control" id="clientPhoneNo" th:field="*{phoneNo}" th:errorclass="fieldError" th:value="${client.phoneNo}">
<input type="text" name="phoneNo" class="form-control" id="clientPhoneNo" th:field="*{phoneNo}" th:errorclass="is-invalid" th:value="${client.phoneNo}">
<div th:replace="common::errors('phoneNo')"></div>
</div>
</div>
<div class="form-group row pull-right">
<div class="form-group row float-right">
<div class="col-sm-12">
<a href="/client" class="btn btn-default" th:text="#{common.back.button}"></a>
<a href="/client" class="btn btn-secondary" th:text="#{common.back.button}"></a>
<button type="submit" class="btn btn-primary" th:text="#{common.save.button}"></button>
</div>
</div>

View File

@ -22,10 +22,11 @@
</script>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{client.title}"></h1>
<div class="pull-right">
</div>
<div layout:fragment="content">
<div class="float-right mb-3">
<a class="btn btn-success" th:href="@{/client/create}" th:text="#{common.create.button}"></a>
</div>
@ -47,7 +48,7 @@
<td th:text="${client.phoneNo}"></td>
<td>
<div class="btn-group pull-right">
<a th:href="@{/client/edit/{id}(id=${client.id})}" class="btn btn-default" th:text="#{common.edit.button}"></a>
<a th:href="@{/client/edit/{id}(id=${client.id})}" class="btn btn-secondary" th:text="#{common.edit.button}"></a>
<button type="button" class="btn btn-danger" th:onclick="'deleteClientById(' + ${client.id} + ')'" th:text="#{common.delete.button}"></button>
</div>
</td>

View File

@ -3,23 +3,23 @@
xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="pagination(totalPages)" th:with="currentPage=${T(Integer).parseInt(#request.getParameter('page') ?: 0)}">
<ul class="pagination pagination-small" th:if="${totalPages > 1}" th:with="urlBuilder=${T(org.springframework.web.servlet.support.ServletUriComponentsBuilder).fromCurrentRequest()}">
<ul class="pagination justify-content-center" th:if="${totalPages > 1}" th:with="urlBuilder=${T(org.springframework.web.servlet.support.ServletUriComponentsBuilder).fromCurrentRequest()}">
<th:block th:each="page : ${#numbers.sequence(0, totalPages - 1, 1)}" th:if="${page == 0 || page == totalPages - 1 || (page >= currentPage - 2 && page <= currentPage + 2)}">
<li class="disabled" th:if="${(page == currentPage - 2 && currentPage > 3) || (page == totalPages - 1 && currentPage < totalPages - 3)}">
<a href="javascript:void(0);">...</a>
<li class="page-item disabled" th:if="${(page == currentPage - 2 && currentPage > 3) || (page == totalPages - 1 && currentPage < totalPages - 3)}">
<a class="page-link" href="javascript:void(0);">...</a>
</li>
<li th:classappend="${currentPage == page ? 'active' : ''}">
<a th:href="${urlBuilder.replaceQueryParam('page', page).toUriString()}" th:text="${page + 1}"></a>
<li class="page-item" th:classappend="${currentPage == page ? 'active' : ''}">
<a class="page-link" th:href="${urlBuilder.replaceQueryParam('page', page).toUriString()}" th:text="${page + 1}"></a>
</li>
</th:block>
</ul>
</div>
<div th:fragment="errors(fieldName)" th:if="${#fields.hasErrors(fieldName)}">
<small class="invalid-feedback" th:fragment="errors(fieldName)" th:if="${#fields.hasErrors(fieldName)}">
<ul>
<li th:each="err : ${#fields.errors(fieldName)}" th:text="${err}"></li>
</ul>
</div>
</small>
<th:block th:fragment="formatDateTime(dateTime)" th:if="${dateTime != null}">
<th:block th:value="${dateTime.format(T(java.time.format.DateTimeFormatter).ofPattern('yyyy-MM-dd HH:mm:ss'))}"/>

View File

@ -5,8 +5,10 @@
<title th:text="#{default.title}"></title>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1>Car Repair test project</h1>
</div>
<div layout:fragment="content">
<h2>
<span><th:block th:text="#{home.requirements.label}"/>:</span>
</h2>

View File

@ -7,52 +7,60 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title th:text="#{default.title}">"</title>
<!-- Common styles and scripts -->
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/3.4.0/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/4.3.1/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="/webjars/font-awesome/5.8.1/css/fontawesome.min.css"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/main.css}"/>
</head>
<body>
<nav class="navbar navbar-inverse">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" th:href="@{/}" th:text="#{default.title}"></a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a th:href="@{/client/}"><th:block th:text="#{badge.clients}"/> <span class="badge" th:text="${clientsCount}"></span></a></li>
<li><a th:href="@{/mechanic/}"><th:block th:text="#{badge.mechanics}"/> <span class="badge" th:text="${mechanicsCount}"></span></a></li>
<li><a th:href="@{/order/}"><th:block th:text="#{badge.orders}"/> <span class="badge" th:text="${ordersCount}"></span></a></li>
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" th:href="@{/client/}">
<th:block th:text="#{badge.clients}"/> <span class="badge badge-light" th:text="${clientsCount}"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/mechanic/}">
<th:block th:text="#{badge.mechanics}"/> <span class="badge badge-light" th:text="${mechanicsCount}"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" th:href="@{/order/}">
<th:block th:text="#{badge.orders}"/> <span class="badge badge-light" th:text="${ordersCount}"></span>
</a>
</li>
</ul>
</div>
</div>
</nav>
<br/>
<div class="container">
<div class="panel panel-default">
<div class="panel-body">
<div class="card">
<div class="card-header">
<div layout:fragment="header">
</div>
</div>
<div class="card-body">
<div layout:fragment="content">
</div>
</div>
</div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="panel panel-default">
<div class="panel-body">
<div class="card-footer">
&copy 2019 <th:block th:text="#{default.title}"/>, Alexey Zinchenko
</div>
</div>
</div>
</div>
</footer>
<th:block>
<script src="/webjars/jquery/3.3.1/jquery.min.js"></script>
<script src="/webjars/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<script src="/webjars/jquery/3.4.0/jquery.min.js"></script>
<script src="/webjars/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<th:block layout:fragment="scripts">
</th:block>

View File

@ -5,41 +5,42 @@
<title th:text="#{default.title}"></title>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{mechanic.title}"></h1>
</div>
<div layout:fragment="content">
<form th:action="'/mechanic/' + ${mechanic.id != null ? 'update/' + mechanic.id : 'create'}" th:object="${mechanic}" method="post">
<div class="form-group row">
<label for="mechanicFirstName" class="col-sm-2 col-form-label" th:text="#{firstName.label}"></label>
<div class="col-sm-10">
<input type="text" name="firstName" class="form-control" id="mechanicFirstName" th:field="*{firstName}" th:errorclass="fieldError" th:value="${mechanic.firstName}">
<input type="text" name="firstName" class="form-control" id="mechanicFirstName" th:field="*{firstName}" th:errorclass="is-invalid" th:value="${mechanic.firstName}">
<div th:replace="common::errors('firstName')"></div>
</div>
</div>
<div class="form-group row">
<label for="mechanicMiddleName" class="col-sm-2 col-form-label" th:text="#{middleName.label}"></label>
<div class="col-sm-10">
<input type="text" name="middleName" class="form-control" id="mechanicMiddleName" th:field="*{middleName}" th:errorclass="fieldError" th:value="${mechanic.middleName}">
<input type="text" name="middleName" class="form-control" id="mechanicMiddleName" th:field="*{middleName}" th:errorclass="is-invalid" th:value="${mechanic.middleName}">
<div th:replace="common::errors('middleName')"></div>
</div>
</div>
<div class="form-group row">
<label for="mechanicLastName" class="col-sm-2 col-form-label" th:text="#{lastName.label}"></label>
<div class="col-sm-10">
<input type="text" name="lastName" class="form-control" id="mechanicLastName" th:field="*{lastName}" th:errorclass="fieldError" th:value="${mechanic.lastName}">
<input type="text" name="lastName" class="form-control" id="mechanicLastName" th:field="*{lastName}" th:errorclass="is-invalid" th:value="${mechanic.lastName}">
<div th:replace="common::errors('lastName')"></div>
</div>
</div>
<div class="form-group row">
<label for="mechanicHourlyPayment" class="col-sm-2 col-form-label" th:text="#{hourlyPayment.label}"></label>
<div class="col-sm-10">
<input type="number" name="hourlyPayment" class="form-control" id="mechanicHourlyPayment" th:field="*{hourlyPayment}" th:errorclass="fieldError" th:value="${mechanic.hourlyPayment}">
<input type="number" name="hourlyPayment" class="form-control" id="mechanicHourlyPayment" th:field="*{hourlyPayment}" th:errorclass="is-invalid" th:value="${mechanic.hourlyPayment}">
<div th:replace="common::errors('hourlyPayment')"></div>
</div>
</div>
<div class="form-group row pull-right">
<div class="form-group row float-right">
<div class="col-sm-12">
<a href="/mechanic" class="btn btn-default" th:text="#{common.back.button}"></a>
<a href="/mechanic" class="btn btn-secondary" th:text="#{common.back.button}"></a>
<button type="submit" class="btn btn-primary" th:text="#{common.save.button}"></button>
</div>
</div>

View File

@ -22,11 +22,12 @@
</script>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{mechanic.title}"></h1>
<div class="pull-right">
<a class="btn btn-success" th:href="@{/mechanic/create}" th:text="#{common.create.button}"></a>
</div>
<div layout:fragment="content">
<div class="float-right mb-3">
<a class="btn btn-success" th:href="@{/mechanic/create}" th:text="#{common.create.button}"></a></a>
</div>
<table class="table table-striped table-hover" th:unless="${mechanicList.isEmpty()}">
@ -48,7 +49,7 @@
<td>
<div class="btn-group pull-right">
<a th:href="@{/mechanic/statistics/{id}(id=${mechanic.id})}" class="btn btn-info" th:text="#{showStatistics.button}"></a>
<a th:href="@{/mechanic/edit/{id}(id=${mechanic.id})}" class="btn btn-default" th:text="#{common.edit.button}"></a>
<a th:href="@{/mechanic/edit/{id}(id=${mechanic.id})}" class="btn btn-secondary" th:text="#{common.edit.button}"></a>
<button type="button" class="btn btn-danger" th:onclick="'deleteMechanicById(' + ${mechanic.id} + ')'" th:text="#{common.delete.button}"></button>
</div>
</td>

View File

@ -5,9 +5,10 @@
<title th:text="#{default.title}"></title>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{mechanic.title}"></h1>
</div>
<div layout:fragment="content">
<table class="table table-striped table-hover">
<thead>
<tr>
@ -30,9 +31,9 @@
</tr>
</tbody>
</table>
<div class="form-group row pull-right">
<div class="form-group row float-right">
<div class="col-sm-12">
<a href="/mechanic" class="btn btn-default" th:text="#{common.back.button}"></a>
<a href="/mechanic" class="btn btn-secondary" th:text="#{common.back.button}"></a>
</div>
</div>
</div>

View File

@ -3,79 +3,89 @@
layout:decorate="~{main}">
<head>
<title th:text="#{default.title}"></title>
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap-datetimepicker/2.4.2/css/bootstrap-datetimepicker.min.css"/>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{order.title}"></h1>
</div>
<div layout:fragment="content">
<form th:action="'/order/' + ${order.id != null ? 'update/' + order.id : 'create'}" th:object="${order}" method="post">
<div class="form-group row">
<label for="orderDescription" class="col-sm-2 col-form-label" th:text="#{description.label}"></label>
<div class="col-sm-10">
<textarea name="description" class="form-control" id="orderDescription" th:field="*{description}" th:errorclass="fieldError" th:value="${order.description}"></textarea>
<textarea name="description" class="form-control" id="orderDescription" th:field="*{description}" th:errorclass="is-invalid" th:value="${order.description}"></textarea>
<div th:replace="common::errors('description')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderClient_tmp" class="col-sm-2 col-form-label" th:text="#{client.label}"></label>
<div class="col-sm-10">
<input type="text" name="client.id_tmp" class="form-control" id="orderClient_tmp"
th:value="${order.client != null ? order.client.firstName + ' ' + order.client.lastName : null}">
<input type="hidden" name="client.id" id="orderClient" th:value="${order.client != null ? order.client.id : null}">
<div class="input-group col-sm-10" th:with="client=${order.client}, clientInitials=${(client != null && client.id != null) ? (client.firstName+ ' ' + client.lastName) : null}">
<span class="input-group-prepend input-group-text" id="orderClientPlaceholder" th:text="${clientInitials}"></span>
<input type="text" name="clientId_tmp" class="form-control" id="orderClient_tmp" th:classappend="${#fields.hasErrors('client') ? 'is-invalid' : null}">
<input type="hidden" name="clientId" id="orderClient" th:value="${client != null && client.id != null ? client.id : ''}">
<div th:replace="common::errors('client')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderMechanic" class="col-sm-2 col-form-label" th:text="#{mechanic.label}"></label>
<div class="col-sm-10">
<input type="text" name="mechanic.id_tmp" class="form-control" id="orderMechanic_tmp"
th:value="${order.mechanic != null ? order.mechanic.firstName + ' ' + order.mechanic.lastName : null}">
<input type="hidden" name="mechanic.id" id="orderMechanic" th:value="${order.mechanic != null ? order.mechanic.id : null}">
<div class="input-group col-sm-10" th:with="mechanic=${order.mechanic}, mechanicInitials=${(mechanic != null && mechanic.id != null) ? (mechanic.firstName+ ' ' + mechanic.lastName) : null}">
<span class="input-group-prepend input-group-text" id="orderMechanicPlaceholder" th:text="${mechanicInitials}"></span>
<input type="text" name="mechanicId_tmp" class="form-control" id="orderMechanic_tmp" th:classappend="${#fields.hasErrors('mechanic') ? 'is-invalid' : null}">
<input type="hidden" name="mechanicId" id="orderMechanic" th:value="${mechanic != null && mechanic.id != null ? mechanic.id : ''}">
<div th:replace="common::errors('mechanic')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderCreatedOn" class="col-sm-2 col-form-label" th:text="#{createdOn.label}"></label>
<div class="col-sm-10">
<input type="datetime-local" name="createdOn" class="form-control" id="orderCreatedOn" th:field="*{createdOn}" th:errorclass="fieldError" th:value="${order.createdOn}">
<div class="input-group col-sm-10">
<input type="datetime-local" name="createdOn" class="form-control" id="orderCreatedOn" th:field="*{createdOn}" th:errorclass="is-invalid" th:value="${order.createdOn}">
<span class="input-group-append input-group-text">
<i class="far fa-calendar"></i>
</span>
<div th:replace="common::errors('createdOn')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderFinishedOn" class="col-sm-2 col-form-label" th:text="#{finishedOn.label}"></label>
<div class="col-sm-10">
<input type="datetime-local" name="finishedOn" class="form-control" id="orderFinishedOn" th:field="*{finishedOn}" th:errorclass="fieldError" th:value="${order.finishedOn}">
<div class="input-group col-sm-10">
<input type="datetime-local" name="finishedOn" class="form-control" id="orderFinishedOn" th:field="*{finishedOn}" th:errorclass="is-invalid" th:value="${order.finishedOn}">
<span class="input-group-append input-group-text">
<i class="far fa-calendar"></i>
</span>
<div th:replace="common::errors('finishedOn')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderTotalPrice" class="col-sm-2 col-form-label" th:text="#{totalPrice.label}"></label>
<div class="col-sm-10">
<input type="number" name="totalPrice" class="form-control" id="orderTotalPrice" th:field="*{totalPrice}" th:errorclass="fieldError" th:value="${order.totalPrice}">
<div class="input-group col-sm-10">
<input type="number" name="totalPrice" class="form-control" id="orderTotalPrice" th:field="*{totalPrice}" th:errorclass="is-invalid" th:value="${order.totalPrice}">
<span class="input-group-append input-group-text">EUR</span>
<div th:replace="common::errors('totalPrice')"></div>
</div>
</div>
<div class="form-group row">
<label for="orderStatus" class="col-sm-2 col-form-label" th:text="#{status.label}"></label>
<div class="col-sm-10">
<select name="orderStatus" class="form-control" id="orderStatus" th:field="*{orderStatus}" th:errorclass="fieldError" th:value="${order.orderStatus}">
<select name="orderStatus" class="form-control custom-select" id="orderStatus" th:field="*{orderStatus}" th:errorclass="is-invalid" th:value="${order.orderStatus}">
<option th:each="orderStatus : ${orderStatuses}" th:value="${orderStatus.toString()}" th:text="${{orderStatus}}"></option>
</select>
<div th:replace="common::errors('orderStatus')"></div>
</div>
</div>
<div class="form-group row pull-right">
<div class="form-group row float-right">
<div class="col-sm-12">
<a href="/order" class="btn btn-default" th:text="#{common.back.button}"></a>
<a href="/order" class="btn btn-secondary" th:text="#{common.back.button}"></a>
<button type="submit" class="btn btn-primary" th:text="#{common.save.button}"></button>
</div>
</div>
</form>
</div>
<th:block layout:fragment="scripts">
<script src="/webjars/jQuery-Autocomplete/1.4.9/jquery.autocomplete.min.js"></script>
<script src="/webjars/bootstrap-datetimepicker/2.4.2/js/bootstrap-datetimepicker.min.js"></script>
<script type="text/javascript">
function initializeAutocomplete(entity, inputId) {
$('#' + inputId + '_tmp').autocomplete({
@ -91,16 +101,24 @@
},
onSelect: function (suggestion) {
$('#' + inputId).val(suggestion.data);
},
onInvalidateSelection: function () {
$('#' + inputId).val('');
$('#' + inputId + 'Placeholder').text(suggestion.value);
$('#' + inputId + '_tmp').val('');
},
showNoSuggestionNotice: true
});
}
function initializeDatetimePicker(field) {
$('#' + field).datetimepicker({
format: 'yyyy-mm-dd hh:mm:ss'
});
}
initializeAutocomplete('client', 'orderClient');
initializeAutocomplete('mechanic', 'orderMechanic');
initializeDatetimePicker('orderCreatedOn');
initializeDatetimePicker('orderFinishedOn');
</script>
</th:block>

View File

@ -22,11 +22,11 @@
</script>
</head>
<body>
<div layout:fragment="content">
<div layout:fragment="header">
<h1 th:text="#{order.title}"></h1>
<div class="row">
<form>
</div>
<div layout:fragment="content">
<form class="mb-5 pb-3">
<div class="form-row">
<div class="col-md-4">
<label for="clientSearchInput" th:text="#{client.label}"></label>
@ -45,22 +45,21 @@
</select>
</div>
</div>
<div class="form-row pull-right">
<div class="form-row float-right mt-2">
<br/>
<div class="col-md-3">
<button type="submit" class="btn btn-primary" th:text="#{common.search.button}"></button>
</div>
</div>
</form>
</div>
<hr/>
<div class="pull-right">
<div class="float-right mb-3">
<a class="btn btn-success" th:href="@{/order/create}" th:text="#{common.create.button}"></a>
</div>
<table class="table table-striped table-hover" th:unless="${orderList.isEmpty()}">
<table class="table" th:unless="${orderList.isEmpty()}">
<thead>
<tr>
<th th:text="#{client.label}"></th>
@ -84,7 +83,7 @@
<td th:text="${{order.totalPrice}}"></td>
<td style="break-inside: avoid">
<div class="btn-group pull-right">
<a th:href="@{/order/edit/{id}(id=${order.id})}" class="btn btn-default" th:text="#{common.edit.button}"></a>
<a th:href="@{/order/edit/{id}(id=${order.id})}" class="btn btn-secondary" th:text="#{common.edit.button}"></a>
<button type="button" class="btn btn-danger" th:onclick="'deleteOrderById(' + ${order.id} + ')'" th:text="#{common.delete.button}"></button>
</div>
</td>