more details

This commit is contained in:
Jörg Henke
2026-01-19 19:21:00 +01:00
parent 2cf5a44cf5
commit 62060311e9
5 changed files with 156 additions and 86 deletions

View File

@@ -30,6 +30,8 @@ public class AppController extends CommonController {
@RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement/workpackage/{pkWorkpackage}/apps")
public String getAppsOfWorkpackage(@PathVariable("pkWorkpackage") Integer pkWorkpackage, final Model model) {
model.addAttribute("bean", service.getWorkpackage(pkWorkpackage));
model.addAttribute("project", service.getProjectOfWorkpackage(pkWorkpackage));
model.addAttribute("apps", service.getAppsOf(pkWorkpackage));
return "/projectmanagement/app/list";
}

View File

@@ -1,5 +1,6 @@
package de.jottyfan.timetrack.modules.projectmanagement;
import static de.jottyfan.timetrack.db.project.Tables.T_PROJECT;
import static de.jottyfan.timetrack.db.project.Tables.T_APP;
import static de.jottyfan.timetrack.db.project.Tables.T_BUNDLE;
import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE;
@@ -25,6 +26,7 @@ import org.springframework.stereotype.Repository;
import de.jottyfan.timetrack.db.project.tables.records.TBundleRecord;
import de.jottyfan.timetrack.db.project.tables.records.TWorkpackageAppRecord;
import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.ProjectBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageAppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean;
@@ -109,7 +111,8 @@ public class AppRepository {
* @return the list of workpackage app linkages
*/
public List<WorkpackageAppBean> getWorkpackageApps(Integer pkApp) {
return jooq.selectFrom(T_WORKPACKAGE_APP).where(T_WORKPACKAGE_APP.FK_APP.eq(pkApp)).fetchInto(WorkpackageAppBean.class);
return jooq.selectFrom(T_WORKPACKAGE_APP).where(T_WORKPACKAGE_APP.FK_APP.eq(pkApp))
.fetchInto(WorkpackageAppBean.class);
}
/**
@@ -156,4 +159,37 @@ public class AppRepository {
jooq.selectFrom(T_BUNDLE).fetchInto(TBundleRecord.class).forEach(b -> map.put(b.getPkBundle(), b));
return map;
}
/**
* get the workpackage
*
* @param pkWorkpackage the ID of the workpackage
* @return the workpackage if found or null
*/
public WorkpackageBean getWorkpackage(Integer pkWorkpackage) {
return jooq
// @formatter:off
.selectFrom(T_WORKPACKAGE)
.where(T_WORKPACKAGE.PK_WORKPACKAGE.eq(pkWorkpackage))
.fetchOneInto(WorkpackageBean.class);
// @formatter:on
}
/**
* get the project of the workpackage
*
* @param pkWorkpackage the ID of the workpackage
* @return the project if found or null
*/
public ProjectBean getProjectOfWorkpackage(Integer pkWorkpackage) {
return jooq
// @formatter:off
.select(T_PROJECT.NAME,
T_PROJECT.DESCRIPTION)
.from(T_WORKPACKAGE)
.leftJoin(T_PROJECT).on(T_PROJECT.PK_PROJECT.eq(T_WORKPACKAGE.FK_PROJECT))
.where(T_WORKPACKAGE.PK_WORKPACKAGE.eq(pkWorkpackage))
.fetchOneInto(ProjectBean.class);
// @formatter:on
}
}

View File

@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
import de.jottyfan.timetrack.db.project.tables.records.TBundleRecord;
import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.ProjectBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageAppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean;
@@ -45,4 +46,11 @@ public class AppService {
return repository.getBundleMap();
}
public WorkpackageBean getWorkpackage(Integer pkWorkpackage) {
return repository.getWorkpackage(pkWorkpackage);
}
public ProjectBean getProjectOfWorkpackage(Integer pkWorkpackage) {
return repository.getProjectOfWorkpackage(pkWorkpackage);
}
}

View File

@@ -6,19 +6,24 @@
<body>
<font layout:fragment="title">Projekt</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}">zur Projektübersicht</a></li>
<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>
</li>
</ul>
<main layout:fragment="content">
<div class="card">
<div class="card-header" th:text="${app.name}"></div>
<div class="card-body">
<div class="container">
<div class="row">
<div class="col-2">Name</div>
<div class="col-10 fw-bold" th:text="${app.name}"></div>
<div class="col-2">Beschreibung</div>
<div class="col-10" th:text="${app.description}"></div>
<div class="col-2">Basisfunktion</div>
<div class="col-10" th:text="${app.basicFunctionality}"></div>
<div class="col-2">URL der Entwicklung</div>
<div class="col-10"><a th:href="${app.repositoryUrl}" target="_blank" th:text="${app.repositoryUrl}"></a></div>
<div class="col-10">
<a th:href="${app.repositoryUrl}" target="_blank" th:text="${app.repositoryUrl}"></a>
</div>
<div class="col-2" th:if="${app.fkReplacedByApp}">Ersetzt durch andere App</div>
<div class="col-10" th:if="${app.fkReplacedByApp}">
<a th:href="@{/projectmanagement/app/{id}/assign(id=${app.fkReplacedByApp})}" th:text="${app.fkReplacedByApp}"></a>
@@ -31,8 +36,9 @@
</th:block>
</div>
</div>
<div class="row">
<div class="col-12">
</div>
</div>
<div class="card-footer">
<table class="table table-striped">
<thead>
<tr>
@@ -43,21 +49,15 @@
</thead>
<tbody>
<tr th:each="p : ${workpackages}">
<td>
<input type="checkbox" th:checked="${p.isIn(linked)}" /> <a th:href="@{/projectmanagement/workpackage/{w}/apps(w=${p.pkWorkpackage})}" th:text="${p.name}"></a>
</td>
<td><input type="checkbox" th:checked="${p.isIn(linked)}" /> <a th:href="@{/projectmanagement/workpackage/{w}/apps(w=${p.pkWorkpackage})}" th:text="${p.name}"></a></td>
<td th:text="${p.description}"></td>
<td>
<a th:href="@{/projectmanagement/workpackage/{w}/app/{a}/toggle(w=${p.pkWorkpackage},a=${app.pkApp})}" class="btn btn-outline-secondary">
<span th:if="${p.isIn(linked)}">rausschmeißen</span>
<span th:unless="${p.isIn(linked)}">zuweisen</span>
</a>
</td>
<td><a th:href="@{/projectmanagement/workpackage/{w}/app/{a}/toggle(w=${p.pkWorkpackage},a=${app.pkApp})}" class="btn btn-outline-secondary">
<span th:if="${p.isIn(linked)}">rausschmeißen</span> <span th:unless="${p.isIn(linked)}">zuweisen</span>
</a></td>
</tr>
</table>
</div>
</div>
</div>
</main>
</body>
</html>

View File

@@ -11,7 +11,30 @@
</li>
</ul>
<main layout:fragment="content">
<div class="p-2">
<div class="card">
<div class="card-header" th:if="${bean}">
<span th:text="${project.name}" th:if="${project}"></span>:
<span th:text="${bean.name}"></span>
</div>
<div class="card-body" th:if="${bean}">
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-2" th:if="${project}">Projektdetails</div>
<div class="col-sm-12 col-md-10" th:if="${project}" th:text="${project.description}"></div>
<div class="col-sm-12 col-md-2">Beschreibung</div>
<div class="col-sm-12 col-md-10" th:text="${bean.description}"></div>
<div class="col-sm-12 col-md-2">Milestone</div>
<div class="col-sm-12 col-md-10">
<a th:href="${bean.milestoneUrl}" target="_blank" th:text="${bean.milestoneUrl}" th:if="${bean.milestoneUrl}"></a>
</div>
<div class="col-sm-12 col-md-2">Vertrag</div>
<div class="col-sm-12 col-md-10" th:text="${bean.contractUrl}"></div>
<div class="col-sm-12 col-md-2">Zieldatum</div>
<div class="col-sm-12 col-md-10" th:text="${bean.plannedDuedate}"></div>
</div>
</div>
</div>
<div class="card-footer">
<table id="table" class="table table-striped">
<thead>
<tr>
@@ -41,6 +64,7 @@
});
</script>
</div>
</div>
</main>
</body>
</html>