Explorer
/proc/2812445/root/tmp/patch_customer_search_sections.py
← Zurück ↓ Download
from pathlib import Path
from datetime import datetime
p=Path('/opt/struktur/projects-dashboard/app.py')
s=p.read_text()
ts=datetime.now().strftime('%Y%m%d-%H%M%S')
Path(f'/opt/struktur/projects-dashboard/app.py.bak-searchsections-{ts}').write_text(s)
marker='CUSTOMER_PROJECTS_INDEX_HTML = '
if 'CUSTOMER_SEARCH_DIRECTIONS = [' not in s:
    block='''CUSTOMER_SEARCH_DIRECTIONS = [\n    {\n        'id': 'business',\n        'title': 'Suchrichtung: Business',\n        'terms': ['Business'],\n        'sort': 'Neueste importierte zuerst',\n        'batches': ['kundenprojekte-business-2026-09-08'],\n        'videos_total': 10,\n        'videos_usable': 9,\n        'videos_missing': 1,\n        'project_ids': [p['id'] for p in CUSTOMER_PROJECTS],\n    },\n]\n\n'''
    s=s.replace(marker,block+marker,1)
start=s.index('CUSTOMER_PROJECTS_INDEX_HTML = """')
end=s.index('\n\nCUSTOMER_PROJECT_DETAIL_HTML =',start)
new='''CUSTOMER_PROJECTS_INDEX_HTML = """<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Kundenprojekte</title><style>\n*{box-sizing:border-box}body{margin:0;background:#0f1117;color:#e2e8f0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}header{padding:2rem 3rem;border-bottom:1px solid #1e2330;display:flex;justify-content:space-between;align-items:center}h1{margin:0;color:#fff;font-size:1.5rem}header span{color:#64748b;font-size:.85rem}.back{color:#60a5fa;text-decoration:none;border:1px solid #1e3a5f;padding:.4rem 1rem;border-radius:8px}.wrap{padding:2.5rem 3rem;max-width:1400px;margin:auto}.intro{color:#94a3b8;line-height:1.6;margin:0 0 1.5rem}.research{margin:0 0 2.2rem}.research-head{background:#131925;border:1px solid #263044;border-radius:12px;padding:1rem 1.2rem;margin-bottom:.8rem}.research-title{font-size:1.08rem;font-weight:700;color:#fff}.research-meta{display:flex;gap:.65rem 1.2rem;flex-wrap:wrap;margin-top:.55rem;color:#94a3b8;font-size:.78rem}.research-meta strong{color:#cbd5e1}.table-head{display:grid;grid-template-columns:minmax(250px,1.6fr) repeat(4,minmax(120px,.75fr)) auto;gap:.8rem;padding:0 .9rem .45rem;color:#64748b;font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em}.grid{display:flex;flex-direction:column;gap:.85rem}.card{background:#161b27;border:1px solid #1e2330;border-radius:12px;padding:1rem 1.15rem;display:grid;grid-template-columns:minmax(250px,1.6fr) repeat(4,minmax(120px,.75fr)) auto;gap:.8rem;align-items:center}.project-main{display:grid;grid-template-columns:auto 1fr;gap:.8rem;align-items:center}.icon{font-size:1.8rem}.title{font-size:1rem;font-weight:600;color:#fff;margin-bottom:.2rem}.desc{font-size:.78rem;color:#94a3b8;line-height:1.4}.metrics{display:contents}.metric{background:#0f1420;border:1px solid #263044;border-radius:8px;padding:.55rem}.metric-label{display:block;color:#64748b;font-size:.64rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.18rem}.metric-value{display:block;color:#e2e8f0;font-size:.78rem;font-weight:650;line-height:1.25}.btn{display:inline-block;margin:0;background:#1e3a5f;color:#60a5fa;border:0;border-radius:6px;padding:.45rem .9rem;text-decoration:none;font-size:.8rem;font-weight:600;white-space:nowrap}footer{text-align:center;padding:2rem;color:#334155;font-size:.8rem}@media(max-width:1000px){.table-head{display:none}.card{grid-template-columns:1fr 1fr}.project-main,.btn{grid-column:1/-1}.metrics{display:grid;grid-template-columns:1fr 1fr;grid-column:1/-1}}@media(max-width:700px){header,.wrap{padding-left:1.25rem;padding-right:1.25rem}header{gap:1rem;align-items:flex-start}.card{grid-template-columns:1fr}.metrics{grid-template-columns:1fr 1fr}}\n</style></head><body><header><div><h1>Kundenprojekte</h1><span>Recherche-Richtungen · Ergebnisse · Entwicklungsstände</span></div><a class="back" href="/">← Projects</a></header><main class="wrap"><p class="intro">Jede Suchrichtung wird als eigener Recherche-Bereich geführt. Neue Suchbegriffe erzeugen einen neuen Bereich; bestehende Projekte werden referenziert und nicht dupliziert.</p>{% for section in search_directions %}<section class="research"><div class="research-head"><div class="research-title">{{section.title}}</div><div class="research-meta"><span><strong>Suchbegriffe:</strong> {{section.terms|join(', ')}}</span><span><strong>Sortierung:</strong> {{section.sort}}</span><span><strong>Ausgewertet:</strong> {{section.videos_total}} Videos</span><span><strong>Verwertbar:</strong> {{section.videos_usable}}</span><span><strong>Transkript fehlt:</strong> {{section.videos_missing}}</span><span><strong>Batch:</strong> {{section.batches|join(', ')}}</span></div></div><div class="table-head"><span>Projekt</span><span>Aufbau</span><span>Umsetzung</span><span>Potenzial</span><span>Erlös</span><span>Details</span></div><div class="grid">{% for p in customer_projects if p.id in section.project_ids %}<article class="card" id="project-card-{{section.id}}-{{p.id}}"><div class="project-main"><div class="icon">{{p.icon}}</div><div><div class="title">{{p.name}}</div><div class="desc">{{p.desc}}</div></div></div><div class="metrics">{% for label,value in p.metrics.items() %}<div class="metric"><span class="metric-label">{{label}}</span><span class="metric-value">{{value}}</span></div>{% endfor %}</div><a class="btn" href="/kundenprojekte/{{p.id}}">Details</a></article>{% endfor %}</div></section>{% endfor %}</main><footer>Agent Solutions · Projects Dashboard</footer></body></html>"""'''
s=s[:start]+new+s[end:]
s=s.replace('return render_template_string(CUSTOMER_PROJECTS_INDEX_HTML, customer_projects=CUSTOMER_PROJECTS)','return render_template_string(CUSTOMER_PROJECTS_INDEX_HTML, customer_projects=CUSTOMER_PROJECTS, search_directions=CUSTOMER_SEARCH_DIRECTIONS)',1)
p.write_text(s)
print('PATCH_OK',ts)