Anstehende Meilensteine im Dashboard anzeigen
ci / quality (push) Failing after 38s
ci / build (push) Has been skipped
deploy / deploy (push) Successful in 52s

Projektübergreifende Liste offener/überfälliger Meilensteine mit Datum,
sortiert nach Fälligkeit. Überfällige rot markiert, relative Tagesangabe
("in 3 Tagen" / "überfällig"), direkt verlinkt aufs Projekt. Sitzt oben
zwischen Showstoppern und kritischen Modi.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 4.8 committed 2026-06-06 20:29:16 +02:00
1 parent e46d107b2d
commit 1b186d8be6
2 files changed
+90 -4

No files matched your search

+38 -4
View File
@@ -1,5 +1,5 @@
import { and, eq, ne, isNull, lt, count, desc } from 'drizzle-orm';
import { area, project, blocker, dayEntry, user, risk, type Area, type Project } from '@cockpit/db';
import { and, eq, ne, isNull, isNotNull, lt, count, asc, desc } from 'drizzle-orm';
import { area, project, blocker, dayEntry, user, risk, milestone, type Area, type Project } from '@cockpit/db';
import { router, protectedProcedure } from '../trpc.js';
import { todayIso, previousWerktag } from '../lib/werktag.js';
import { aggregateAreaAmpel } from '../lib/ampel.js';
@@ -7,8 +7,16 @@ import { aggregateAreaAmpel } from '../lib/ampel.js';
export const dashboardRouter = router({
overview: protectedProcedure.query(async ({ ctx }) => {
const todayDate = todayIso();
const [areas, allProjects, openBlockers, todayPresence, totalActiveUsers, feedRows, showstopperRows] =
await Promise.all([
const [
areas,
allProjects,
openBlockers,
todayPresence,
totalActiveUsers,
feedRows,
showstopperRows,
milestoneRows,
] = await Promise.all([
ctx.db.select().from(area).orderBy(area.order),
ctx.db.select().from(project).where(eq(project.archiviert, false)),
ctx.db.select().from(blocker).where(isNull(blocker.resolvedAt)),
@@ -52,6 +60,28 @@ export const dashboardRouter = router({
eq(project.archiviert, false),
),
),
// Anstehende Meilensteine (offen/überfällig, mit Datum) projektübergreifend.
ctx.db
.select({
id: milestone.id,
title: milestone.title,
due: milestone.due,
status: milestone.status,
projectId: milestone.projectId,
projectName: project.name,
areaId: project.areaId,
})
.from(milestone)
.innerJoin(project, eq(project.id, milestone.projectId))
.where(
and(
ne(milestone.status, 'done'),
isNotNull(milestone.due),
eq(project.archiviert, false),
),
)
.orderBy(asc(milestone.due))
.limit(15),
]);
const projectsByArea = new Map<string, Project[]>();
@@ -98,6 +128,10 @@ export const dashboardRouter = router({
},
jourfixe: { nextDate: nextJourfixe(todayDate), label: 'Di 11:00' },
showstoppers: showstopperRows,
meilensteine: milestoneRows.map((m) => ({
...m,
ueberfaellig: m.due != null && m.due < todayDate,
})),
kritischeModi: allProjects
.filter((p) => p.modus === 'eskalation' || p.modus === 'taskforce')
.map((p) => ({ id: p.id, name: p.name, areaId: p.areaId, modus: p.modus })),