feat: v3.0 - canvas editor, JSON-only, no Excel, new UI
Some checks failed
Build & Push Docker / build (push) Has been cancelled

- Remove all Excel code (import, export, template, pandas, openpyxl)
- New canvas-based schedule editor with drag & drop (interact.js)
- Modern 3-panel UI: sidebar, canvas, documentation tab
- New data model: Block with id/date/start/end, ProgramType with id/name/color
- Clean API: GET /api/health, POST /api/validate, GET /api/sample, POST /api/generate-pdf
- Rewritten PDF generator using ScenarioDocument directly (no DataFrame)
- Professional PDF output: dark header, colored blocks, merged cells, legend, footer
- Sample JSON: "Zimní výjezd oddílu" with 11 blocks, 3 program types
- 30 tests passing (API, core models, PDF generation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 17:02:51 +01:00
parent e2bdadd0ce
commit 25fd578543
27 changed files with 2004 additions and 3016 deletions

View File

@@ -2,12 +2,11 @@
from io import BytesIO
import pandas as pd
from fastapi import APIRouter, HTTPException
from fastapi.responses import StreamingResponse
from app.models.event import ScenarioDocument
from app.core.validator import validate_inputs, ValidationError, ScenarsError
from app.core.validator import ScenarsError
from app.core.pdf_generator import generate_pdf
router = APIRouter()
@@ -17,35 +16,7 @@ router = APIRouter()
async def generate_pdf_endpoint(doc: ScenarioDocument):
"""Generate PDF timetable from ScenarioDocument."""
try:
validate_inputs(doc.event.title, doc.event.detail, 0)
except ValidationError as e:
raise HTTPException(status_code=422, detail=str(e))
# Convert to DataFrame
rows = []
for block in doc.blocks:
rows.append({
'Datum': block.datum,
'Zacatek': block.zacatek,
'Konec': block.konec,
'Program': block.program,
'Typ': block.typ,
'Garant': block.garant,
'Poznamka': block.poznamka,
})
df = pd.DataFrame(rows)
if df.empty:
raise HTTPException(status_code=422, detail="No blocks provided")
# Build program descriptions and colors
program_descriptions = {pt.code: pt.description for pt in doc.program_types}
program_colors = {pt.code: 'FF' + pt.color.lstrip('#') for pt in doc.program_types}
try:
pdf_bytes = generate_pdf(df, doc.event.title, doc.event.detail,
program_descriptions, program_colors)
pdf_bytes = generate_pdf(doc)
except ScenarsError as e:
raise HTTPException(status_code=422, detail=str(e))