add, edit and delete apps
This commit is contained in:
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -3,10 +3,14 @@ package de.jottyfan.timetrack.modules.projectmanagement;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
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.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
import de.jottyfan.timetrack.modules.CommonController;
|
import de.jottyfan.timetrack.modules.CommonController;
|
||||||
|
import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean;
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,6 +23,43 @@ public class AppController extends CommonController {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AppService service;
|
private AppService service;
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@GetMapping("/projectmanagement/app/add")
|
||||||
|
public String getAppForAdd(final Model model) {
|
||||||
|
model.addAttribute("bean", new AppBean());
|
||||||
|
model.addAttribute("apps", service.getApps());
|
||||||
|
model.addAttribute("bundles", service.getBundleMap().values());
|
||||||
|
return "/projectmanagement/app/item";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@GetMapping("/projectmanagement/app/{pkApp}")
|
||||||
|
public String getAppForEdit(@PathVariable("pkApp") Integer pkApp, final Model model) {
|
||||||
|
model.addAttribute("bean", service.getApp(pkApp));
|
||||||
|
model.addAttribute("apps", service.getApps());
|
||||||
|
model.addAttribute("bundles", service.getBundleMap().values());
|
||||||
|
return "/projectmanagement/app/item";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@PostMapping("/projectmanagement/app/upsert")
|
||||||
|
public String updateApp(@ModelAttribute("bean") AppBean bean, BindingResult bindingResult, final Model model) {
|
||||||
|
if (bindingResult.hasErrors()) {
|
||||||
|
model.addAttribute("apps", service.getApps());
|
||||||
|
model.addAttribute("bundles", service.getBundleMap().values());
|
||||||
|
return "/projectmanagement/app/item";
|
||||||
|
}
|
||||||
|
service.upsert(bean);
|
||||||
|
return "redirect:/projectmanagement/apps";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@GetMapping("/projectmanagement/app/{pkApp}/delete")
|
||||||
|
public String deleteApp(@PathVariable("pkApp") Integer pkApp) {
|
||||||
|
service.deleteApp(pkApp);
|
||||||
|
return "redirect:/projectmanagement/apps";
|
||||||
|
}
|
||||||
|
|
||||||
@RolesAllowed("timetrack_user")
|
@RolesAllowed("timetrack_user")
|
||||||
@GetMapping("/projectmanagement/apps")
|
@GetMapping("/projectmanagement/apps")
|
||||||
|
|||||||
@@ -192,4 +192,64 @@ public class AppRepository {
|
|||||||
.fetchOneInto(ProjectBean.class);
|
.fetchOneInto(ProjectBean.class);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all apps ordered by name
|
||||||
|
*
|
||||||
|
* @return the apps list; an empty list at least
|
||||||
|
*/
|
||||||
|
public List<AppBean> getAllApps() {
|
||||||
|
return jooq.selectFrom(T_APP).orderBy(T_APP.NAME).fetchInto(AppBean.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete the app
|
||||||
|
*
|
||||||
|
* @param pkApp the ID of the app
|
||||||
|
*/
|
||||||
|
public void deleteApp(Integer pkApp) {
|
||||||
|
jooq.deleteFrom(T_APP).where(T_APP.PK_APP.eq(pkApp)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update the app bean
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
*/
|
||||||
|
public void updateApp(AppBean bean) {
|
||||||
|
jooq
|
||||||
|
// @formatter:off
|
||||||
|
.update(T_APP)
|
||||||
|
.set(T_APP.NAME, bean.getName())
|
||||||
|
.set(T_APP.DESCRIPTION, bean.getDescription())
|
||||||
|
.set(T_APP.FK_BUNDLE, bean.getFkBundle())
|
||||||
|
.set(T_APP.BASIC_FUNCTIONALITY, bean.getBasicFunctionality())
|
||||||
|
.set(T_APP.FK_REPLACED_BY_APP, bean.getFkReplacedByApp())
|
||||||
|
.set(T_APP.REPOSITORY_URL, bean.getRepositoryUrl())
|
||||||
|
.where(T_APP.PK_APP.eq(bean.getPkApp()))
|
||||||
|
.execute();
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert the bean
|
||||||
|
*
|
||||||
|
* @param bean the bean
|
||||||
|
* @return the new ID of the bean
|
||||||
|
*/
|
||||||
|
public Integer insertApp(AppBean bean) {
|
||||||
|
return jooq
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_APP,
|
||||||
|
T_APP.NAME,
|
||||||
|
T_APP.DESCRIPTION,
|
||||||
|
T_APP.FK_BUNDLE,
|
||||||
|
T_APP.BASIC_FUNCTIONALITY,
|
||||||
|
T_APP.FK_REPLACED_BY_APP,
|
||||||
|
T_APP.REPOSITORY_URL)
|
||||||
|
.values(bean.getName(), bean.getDescription(), bean.getFkBundle(), bean.getBasicFunctionality(), bean.getFkReplacedByApp(), bean.getRepositoryUrl())
|
||||||
|
.returning(T_APP.PK_APP)
|
||||||
|
.fetchOne(T_APP.PK_APP);
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,5 +52,21 @@ public class AppService {
|
|||||||
|
|
||||||
public ProjectBean getProjectOfWorkpackage(Integer pkWorkpackage) {
|
public ProjectBean getProjectOfWorkpackage(Integer pkWorkpackage) {
|
||||||
return repository.getProjectOfWorkpackage(pkWorkpackage);
|
return repository.getProjectOfWorkpackage(pkWorkpackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AppBean> getApps() {
|
||||||
|
return repository.getAllApps();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteApp(Integer pkApp) {
|
||||||
|
repository.deleteApp(pkApp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void upsert(AppBean bean) {
|
||||||
|
if (bean.getPkApp() != null) {
|
||||||
|
repository.updateApp(bean);
|
||||||
|
} else {
|
||||||
|
repository.insertApp(bean);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
81
src/main/resources/templates/projectmanagement/app/item.html
Normal file
81
src/main/resources/templates/projectmanagement/app/item.html
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||||
|
<head>
|
||||||
|
<title>Projektmanagement</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<font layout:fragment="title">App</font>
|
||||||
|
<ul layout:fragment="menu">
|
||||||
|
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
|
||||||
|
<a class="nav-link btn btn-secondary btn-white-text" th:href="@{/projectmanagement/apps}">abbrechen</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<main layout:fragment="content">
|
||||||
|
<div class="container">
|
||||||
|
<div class="alert alert-danger" th:if="${error}" th:text="${error}"></div>
|
||||||
|
<form th:action="@{/projectmanagement/app/upsert}" method="post" th:object="${bean}">
|
||||||
|
<div class="container m-2">
|
||||||
|
<div class="row g-2">
|
||||||
|
<div class="col-2" th:if="${bean.pkApp}">ID</div>
|
||||||
|
<div class="col-10" th:if="${bean.pkApp}">
|
||||||
|
<input type="text" class="form-control" th:field="*{pkApp}" readonly="readonly" />
|
||||||
|
</div>
|
||||||
|
<div class="col-2">Name</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<input type="text" class="form-control" th:field="*{name}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-2">Beschreibung</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<textarea class="form-control" th:field="*{description}"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-2">Git-URL</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<input type="text" class="form-control" th:field="*{repositoryUrl}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-2">Basisfunktion</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<textarea class="form-control" th:field="*{basicFunctionality}"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-2">Bundle</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<select th:field="*{fkBundle}" class="form-select">
|
||||||
|
<option value="" label="--- bitte wählen ---" />
|
||||||
|
<option th:each="b : ${bundles}" th:label="${b.name}" th:value="${b.pkBundle}" />
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-2">ersetzt durch</div>
|
||||||
|
<div class="col-10">
|
||||||
|
<select th:field="*{fkReplacedByApp}" class="form-select">
|
||||||
|
<option value="" label="--- bitte wählen ---" />
|
||||||
|
<option th:each="a : ${apps}" th:value="${a.pkApp}" th:title="${a.repositoryUrl}" th:label="${a.name}" />
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-2"></div>
|
||||||
|
<div class="col-5">
|
||||||
|
<input type="submit" class="btn btn-primary" value="Speichern">
|
||||||
|
</div>
|
||||||
|
<div class="col-5" th:if="${bean.pkApp}">
|
||||||
|
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">Löschen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="deleteModalLabel">Bestätigung für Löschvorgang</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">Bist du sicher, dass du dieses Element löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||||
|
<a th:href="@{/projectmanagement/app/{p}/delete(p=${bean.pkApp})}" class="btn btn-danger">Löschen</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
<font layout:fragment="title">Projekt</font>
|
<font layout:fragment="title">Projekt</font>
|
||||||
<ul layout:fragment="menu">
|
<ul layout:fragment="menu">
|
||||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
|
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
|
||||||
<a class="nav-link btn btn-secondary btn-white-text" th:href="@{/projectmanagement}">zur Projektübersicht</a>
|
<a class="btn btn-outline-secondary" th:href="@{/projectmanagement}">zur Projektübersicht</a>
|
||||||
|
<a class="btn btn-outline-primary" th:href="@{/projectmanagement/app/add}" th:unless="${bean}">neue App anlegen</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
@@ -48,7 +49,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="b : ${apps}">
|
<tr th:each="b : ${apps}">
|
||||||
<td th:text="${b.workpackagesString}" th:unless="${bean}"></td>
|
<td th:text="${b.workpackagesString}" th:unless="${bean}"></td>
|
||||||
<td th:text="${b.name}"></td>
|
<td><a th:href="@{/projectmanagement/app/{id}(id=${b.pkApp})}" th:text="${b.name}"></a></td>
|
||||||
<td th:text="${b.description}"></td>
|
<td th:text="${b.description}"></td>
|
||||||
<td><a th:href="${b.repositoryUrl}" target="_blank">gitlab</a></td>
|
<td><a th:href="${b.repositoryUrl}" target="_blank">gitlab</a></td>
|
||||||
<td><a th:href="@{/projectmanagement/app/{id}/assign(id=${b.pkApp})}">zuordnen</a></td>
|
<td><a th:href="@{/projectmanagement/app/{id}/assign(id=${b.pkApp})}">zuordnen</a></td>
|
||||||
|
|||||||
Reference in New Issue
Block a user