feat(kanban): reporte diario al click en dia del calendario (issue 0093)
Adds a daily report dashboard accessible by clicking a day number in the
calendar view. Renders inside a full-width modal (90% width).
Backend (new file backend/reports.go):
- Type DailyReport with KPIs, rankings, done_cards list, reopened cards,
3-bucket stale list (7/14/30d), lead time avg+p50+p95, 24-hour
movement histogram, deadlines met/missed list, tag distribution and
archived count.
- DB.DailyReportFor(date, tz) uses Europe/Madrid by default; computes
[start,end) in local time, converts to UTC and queries:
* cards.completed_at in range -> done list
* card_events kind=created in range -> created counts
* card_column_history.entered_at in range -> moves + hourly
* previousColumnWasDone() -> reopened detection
* card_lock_history overlapping the day -> blocked_ms
* stale buckets: open history entries on non-done columns aged >=7d
- New route GET /api/reports/daily?date=YYYY-MM-DD&tz=Europe/Madrid.
Frontend:
- api.ts: DailyReport type + dailyReport(date, tz?) call.
- New component DailyReportView (components/DailyReport.tsx):
* 6 KPI cards (Hechas, Creadas, Movimientos, Bloqueado, Reabiertas,
Deadlines on-time %).
* 4 ranking cards (Top assignees done, Top assignees created,
Top requesters atendidas, Top requesters aportadas).
* Done cards table with click-to-jump (links open the card in board).
* Mantine BarChart with movements per hour.
* Tag chips, reopened list, deadlines list with late_ms, stale buckets.
- CalendarView wraps the day number in UnstyledButton with data-test
attribute and forwards onOpenDailyReport.
- App.handleOpenDailyReport opens modals.open size 90% with the view;
click on a card title closes the modal and jumps to the board with
highlight (reuses existing handleJumpToCard).
Tests (e2e/daily-report.spec.ts):
- Endpoint shape: kpis, done_cards, hourly_moves[24], stale buckets.
- Calendar day click opens the modal with "Reporte diario" title and
KPI labels visible.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-1
@@ -72,6 +72,7 @@ import { CardForm } from "./components/CardForm";
|
||||
import { CardEditPanel } from "./components/CardEditPanel";
|
||||
import { ChatPanel } from "./components/ChatPanel";
|
||||
import { CalendarView } from "./components/CalendarView";
|
||||
import { DailyReportView } from "./components/DailyReport";
|
||||
import { Dashboard } from "./components/Dashboard";
|
||||
import { HistoryModal } from "./components/HistoryModal";
|
||||
import { KanbanCard } from "./components/KanbanCard";
|
||||
@@ -720,6 +721,22 @@ export function App() {
|
||||
window.setTimeout(() => setHighlightCardId(null), 3000);
|
||||
}, []);
|
||||
|
||||
const handleOpenDailyReport = useCallback((date: string) => {
|
||||
const id = modals.open({
|
||||
title: "Reporte diario",
|
||||
size: "90%",
|
||||
children: (
|
||||
<DailyReportView
|
||||
date={date}
|
||||
onJumpToCard={(cardId) => {
|
||||
modals.close(id);
|
||||
handleJumpToCard(cardId);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}, [handleJumpToCard]);
|
||||
|
||||
const handleSetCardDeadline = useCallback(async (id: string, deadline: string | null) => {
|
||||
setBoard((prev) => {
|
||||
if (!prev) return prev;
|
||||
@@ -1324,7 +1341,7 @@ export function App() {
|
||||
</Box>
|
||||
) : activeTab === "calendar" ? (
|
||||
<Box style={{ height: "calc(100vh - 50px)", overflow: "auto" }}>
|
||||
<CalendarView users={users} cards={board.cards} onJumpToCard={handleJumpToCard} />
|
||||
<CalendarView users={users} cards={board.cards} onJumpToCard={handleJumpToCard} onOpenDailyReport={handleOpenDailyReport} />
|
||||
</Box>
|
||||
) : (
|
||||
<Box style={{ height: "calc(100vh - 50px)", overflow: "hidden", display: "flex", flexDirection: "column" }}>
|
||||
|
||||
Reference in New Issue
Block a user