assignment

This commit is contained in:
henkej
2026-01-16 11:02:11 +01:00
parent 9699032250
commit 0b7cde7ad0
6 changed files with 137 additions and 14 deletions

View File

@@ -39,6 +39,14 @@ public class AppController extends CommonController {
public String loadAssignmentToolForApp(@PathVariable("pkApp") Integer pkApp, final Model model) {
model.addAttribute("app", service.getApp(pkApp));
model.addAttribute("workpackages", service.getWorkpackages());
model.addAttribute("linked", service.getWorkpackageApps(pkApp));
return "/projectmanagement/app/assign";
}
@RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement/workpackage/{pkWorkpackage}/app/{pkApp}/toggle")
public String toggleWorkpackageAppLinkage(@PathVariable("pkWorkpackage") Integer pkWorkpackage, @PathVariable("pkApp") Integer pkApp, final Model model) {
service.toggleWorkpackageAppLinkage(pkWorkpackage, pkApp);
return String.format("redirect:/projectmanagement/app/%s/assign", pkApp);
}
}

View File

@@ -1,19 +1,24 @@
package de.jottyfan.timetrack.modules.projectmanagement;
import static de.jottyfan.timetrack.db.project.Tables.T_APP;
import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE_APP;
import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE;
import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE_APP;
import java.util.List;
import org.jooq.DSLContext;
import org.jooq.DeleteConditionStep;
import org.jooq.InsertValuesStep2;
import org.jooq.Record1;
import org.jooq.Record7;
import org.jooq.SelectConditionStep;
import org.jooq.impl.DSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import de.jottyfan.timetrack.db.project.tables.records.TWorkpackageAppRecord;
import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageAppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean;
/**
@@ -79,4 +84,48 @@ public class AppRepository {
public List<WorkpackageBean> getWorkpackages() {
return jooq.selectFrom(T_WORKPACKAGE).fetchInto(WorkpackageBean.class);
}
/**
* get all workpackage app linkages
*
* @param pkApp the ID of the app to look for
* @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);
}
/**
* toggle workpackage app linkage
*
* @param pkWorkpackage the ID of the workpackage
* @param pkApp the ID of the app
*/
public void toggleWorkpackageAppLinkage(Integer pkWorkpackage, Integer pkApp) {
SelectConditionStep<Record1<Integer>> sql = jooq
// @formatter:off
.select(T_WORKPACKAGE_APP.PK_WORKPACKAGE_APP)
.from(T_WORKPACKAGE_APP)
.where(T_WORKPACKAGE_APP.FK_WORKPACKAGE.eq(pkWorkpackage))
.and(T_WORKPACKAGE_APP.FK_APP.eq(pkApp));
// @formatter:on
Integer pkWorkpackageApp = sql.fetchOne(T_WORKPACKAGE_APP.PK_WORKPACKAGE_APP);
if (pkWorkpackageApp == null) {
InsertValuesStep2<TWorkpackageAppRecord, Integer, Integer> sql2 = jooq
// @formatter:off
.insertInto(T_WORKPACKAGE_APP,
T_WORKPACKAGE_APP.FK_WORKPACKAGE,
T_WORKPACKAGE_APP.FK_APP)
.values(pkWorkpackage, pkApp);
// @formatter:on
sql2.execute();
} else {
DeleteConditionStep<TWorkpackageAppRecord> sql2 = jooq
// @formatter:off
.deleteFrom(T_WORKPACKAGE_APP)
.where(T_WORKPACKAGE_APP.PK_WORKPACKAGE_APP.eq(pkWorkpackageApp));
// @formatter:on
sql2.execute();
}
}
}

View File

@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageAppBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean;
/**
@@ -29,4 +30,13 @@ public class AppService {
public List<WorkpackageBean> getWorkpackages() {
return repository.getWorkpackages();
}
public List<WorkpackageAppBean> getWorkpackageApps(Integer fkApp) {
return repository.getWorkpackageApps(fkApp);
}
public void toggleWorkpackageAppLinkage(Integer pkWorkpackage, Integer pkApp) {
repository.toggleWorkpackageAppLinkage(pkWorkpackage, pkApp);
}
}

View File

@@ -0,0 +1,46 @@
package de.jottyfan.timetrack.modules.projectmanagement.model;
import java.io.Serializable;
/**
*
* @author jotty
*
*/
public class WorkpackageAppBean implements Serializable {
private static final long serialVersionUID = 1L;
private Integer pkWorkpackageApp;
private Integer fkApp;
private Integer fkWorkpackage;
public static final WorkpackageAppBean of(Integer fkApp) {
WorkpackageAppBean bean = new WorkpackageAppBean();
bean.setFkApp(fkApp);
return bean;
}
public Integer getPkWorkpackageApp() {
return pkWorkpackageApp;
}
public void setPkWorkpackageApp(Integer pkWorkpackageApp) {
this.pkWorkpackageApp = pkWorkpackageApp;
}
public Integer getFkApp() {
return fkApp;
}
public void setFkApp(Integer fkApp) {
this.fkApp = fkApp;
}
public Integer getFkWorkpackage() {
return fkWorkpackage;
}
public void setFkWorkpackage(Integer fkWorkpackage) {
this.fkWorkpackage = fkWorkpackage;
}
}

View File

@@ -2,6 +2,8 @@ package de.jottyfan.timetrack.modules.projectmanagement.model;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import de.jottyfan.timetrack.db.project.tables.records.TWorkpackageRecord;
@@ -39,6 +41,10 @@ public class WorkpackageBean implements Serializable {
return bean;
}
public Boolean isIn(List<WorkpackageAppBean> linkages) {
return linkages.stream().map(WorkpackageAppBean::getFkWorkpackage).collect(Collectors.toSet()).contains(pkWorkpackage);
}
/**
* @return the name
*/

View File

@@ -6,14 +6,18 @@
<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="row">
<div class="col">
<div th:text="${app.name}"></div>
<div th:each="p : ${workpackages}" th:text="${p.name}"></div>
TODO: assign app to workpackage and store it
<div th:each="p : ${workpackages}">
<input type="checkbox" th:checked="${p.isIn(linked)}" /> <span th:text="${p.name}"></span> <a
th:href="@{/projectmanagement/workpackage/{w}/app/{a}/toggle(w=${p.pkWorkpackage},a=${app.pkApp})}" class="btn btn-outline-secondary">umschalten</a>
</div>
</div>
</div>
</main>
</body>
</html>