Dashboard

This commit is contained in:
2026-04-06 22:06:25 +02:00
parent d098cf647c
commit fb0b3b4b7b
9 changed files with 27 additions and 21 deletions

1
.gitignore vendored
View File

@@ -25,3 +25,4 @@ hs_err_pid*
replay_pid*
/peakup-backend/src/test/resources/
/peakup-maven/target/

View File

@@ -71,9 +71,7 @@ public class IntervalsActivityResource extends AbstractResource {
@PathParam("id") final long id,
@PathParam("workoutId") final long workoutId) {
try {
final IntervalsActivity activity = intervalsActivityService.getById(id);
intervalsActivityService.linkWorkout(activity, workoutId);
return RestResponse.ok(activity);
return RestResponse.ok(intervalsActivityService.linkWorkout(id, workoutId));
} catch (final NoResultException e) {
return RestResponse.notFound();
}
@@ -83,9 +81,7 @@ public class IntervalsActivityResource extends AbstractResource {
@Path("/{id}/unlink-workout")
public RestResponse<IntervalsActivity> unlinkWorkout(@PathParam("id") final long id) {
try {
final IntervalsActivity activity = intervalsActivityService.getById(id);
intervalsActivityService.unlinkWorkout(activity);
return RestResponse.ok(activity);
return RestResponse.ok(intervalsActivityService.unlinkWorkout(id));
} catch (final NoResultException e) {
return RestResponse.notFound();
}

View File

@@ -43,14 +43,18 @@ public class IntervalsActivityService extends AbstractService<IntervalsActivity,
}
@Transactional
public void linkWorkout(final IntervalsActivity activity, final long workoutId) {
public IntervalsActivity linkWorkout(final long activityId, final long workoutId) {
final IntervalsActivity activity = intervalsActivityDAO.getById(activityId);
activity.setLinkedWorkoutId(workoutId);
update(activity);
return activity;
}
@Transactional
public void unlinkWorkout(final IntervalsActivity activity) {
public IntervalsActivity unlinkWorkout(final long activityId) {
final IntervalsActivity activity = intervalsActivityDAO.getById(activityId);
activity.setLinkedWorkoutId(null);
update(activity);
return activity;
}
}

View File

@@ -56,7 +56,8 @@ public abstract class AbstractDAO<T extends AbstractEntity> {
public void update(final T entity) {
if (!em.contains(entity)) {
throw new PersistenceException(
"Entity is not managed (attached). Use merge() or re-fetch before update: " + entity
"Entity is not managed (attached). Use merge() or re-fetch before update: "
+ entity.getClass().getSimpleName() + "#" + entity.getId()
);
}
// Änderungen werden automatisch von JPA übernommen

View File

@@ -42,6 +42,7 @@ public class ActivityImportScheduler {
log.warn("Import already running, skipping this trigger.");
return;
}
log.info("Start import ...");
try {
for (final StravaConnector connector : stravaConnectorService.getStravaConnectors()) {
try {

View File

@@ -112,12 +112,11 @@ public class WeekPlanResource extends AbstractResource {
@PathParam("workoutId") final long workoutId,
final Workout workout) {
try {
final Workout existing = workoutService.getById(workoutId);
if (existing.getWeekPlanId() != planId) {
final Workout updated = workoutService.updateWorkout(planId, workoutId, workout);
if (updated == null) {
return RestResponse.notFound();
}
workoutService.updateWorkout(existing, workout);
return RestResponse.ok(existing);
return RestResponse.ok(updated);
} catch (final NoResultException e) {
return RestResponse.notFound();
}

View File

@@ -3,6 +3,7 @@ package com.peakup.workout.service;
import com.peakup.common.service.AbstractService;
import com.peakup.workout.dao.WorkoutDAO;
import com.peakup.workout.model.Workout;
import jakarta.annotation.Nullable;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
@@ -26,7 +27,11 @@ public class WorkoutService extends AbstractService<Workout, WorkoutDAO> {
}
@Transactional
public void updateWorkout(final Workout existing, final Workout updated) {
public @Nullable Workout updateWorkout(final long planId, final long workoutId, final Workout updated) {
final Workout existing = workoutDAO.getById(workoutId);
if (existing.getWeekPlanId() != planId) {
return null;
}
existing.setTitle(updated.getTitle());
existing.setDescription(updated.getDescription());
existing.setWorkoutAt(updated.getWorkoutAt());
@@ -37,5 +42,6 @@ public class WorkoutService extends AbstractService<Workout, WorkoutDAO> {
existing.setEstimatedTimeSeconds(updated.getEstimatedTimeSeconds());
existing.setEstimatedTss(updated.getEstimatedTss());
update(existing);
return existing;
}
}

View File

@@ -1,7 +1,3 @@
quarkus.log.category."org.jboss.resteasy.reactive".level=WARN
quarkus.log.category."com.fasterxml.jackson".level=WARN
quarkus.log.category."org.hibernate".level=WARN
quarkus.log.console.level=WARN
quarkus.http.port=8111
quarkus.http.cors=true
quarkus.http.cors.origins=*

View File

@@ -373,7 +373,9 @@ export function Dashboard({athleteId}: { athleteId: number }) {
const loadData = buildLoadData(activities, wStart)
const ctlValues = loadData.map(d => d.ctl).filter((v): v is number => v !== null)
const ctlLoadData = loadData.slice(loadData.findIndex(d => d.ctl !== null))
const ctlValues = ctlLoadData.map(d => d.ctl).filter((v): v is number => v !== null)
const ctlDomain: [number, number] | ['auto', 'auto'] = ctlValues.length
? [Math.floor(Math.min(...ctlValues) * 0.9), Math.ceil(Math.max(...ctlValues) * 1.1)]
: ['auto', 'auto']
@@ -511,9 +513,9 @@ export function Dashboard({athleteId}: { athleteId: number }) {
<p className="text-xs font-semibold tracking-widest text-zinc-400 uppercase mb-5">
Fitness, Fatigue &amp; Form (CTL / ATL / TSB)
</p>
{loadData.some((d) => d.ctl !== null) ? (
{ctlLoadData.some((d) => d.ctl !== null) ? (
<ResponsiveContainer width="100%" height={200}>
<ComposedChart data={loadData} margin={{left: -20, right: 0}}>
<ComposedChart data={ctlLoadData} margin={{left: -20, right: 0}}>
<defs>
<linearGradient id="tssAreaGrad2" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#ef4444" stopOpacity={0.12}/>