Fix: Remove broken getKlausurApiUrl and clean up empty lines
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 42s
CI / test-go-edu-search (push) Successful in 34s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 29s
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 42s
CI / test-go-edu-search (push) Successful in 34s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 29s
sed replacement left orphaned hostname references in story page and empty lines in getApiBase functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
'use client'
|
||||
|
||||
export function SchedulerTab() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Status Overview */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<StatusCard
|
||||
icon={<ClockIcon />}
|
||||
title="launchd Job"
|
||||
description="Taeglich um 07:00 Uhr automatisch"
|
||||
/>
|
||||
<StatusCard
|
||||
icon={<TerminalIcon />}
|
||||
title="Git Hook"
|
||||
description="Quick Tests bei voice-service Aenderungen"
|
||||
/>
|
||||
<StatusCard
|
||||
icon={<BellIcon />}
|
||||
title="Benachrichtigungen"
|
||||
description="Desktop-Alerts bei Fehlern aktiviert"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<div className="bg-slate-50 rounded-lg p-4">
|
||||
<h3 className="font-medium text-slate-800 mb-4">Quick Actions (BQAS)</h3>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<a
|
||||
href="/ai/test-quality"
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center gap-2"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Test Dashboard oeffnen
|
||||
</a>
|
||||
<span className="text-sm text-slate-500 self-center">
|
||||
Starte Tests direkt im BQAS Dashboard
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* GitHub Actions vs Local - Comparison */}
|
||||
<ComparisonTable />
|
||||
|
||||
{/* Configuration Details */}
|
||||
<ConfigurationDetails />
|
||||
|
||||
{/* Detailed Explanation */}
|
||||
<DetailedExplanation />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Sub-components
|
||||
// ============================================================================
|
||||
|
||||
function StatusCard({ icon, title, description }: { icon: React.ReactNode; title: string; description: string }) {
|
||||
return (
|
||||
<div className="rounded-xl border p-5 bg-emerald-100 border-emerald-200 text-emerald-700">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex-shrink-0">
|
||||
{icon}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<h4 className="font-semibold">{title}</h4>
|
||||
<span className="w-2 h-2 rounded-full bg-emerald-500" />
|
||||
</div>
|
||||
<p className="text-sm mt-1 opacity-80">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ComparisonTable() {
|
||||
return (
|
||||
<div className="bg-slate-50 rounded-lg p-4">
|
||||
<h3 className="font-medium text-slate-800 mb-4">GitHub Actions Alternative</h3>
|
||||
<p className="text-slate-600 mb-4">
|
||||
Der lokale BQAS Scheduler ersetzt GitHub Actions und bietet DSGVO-konforme, vollstaendig lokale Test-Ausfuehrung.
|
||||
</p>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-slate-200 bg-white">
|
||||
<th className="text-left py-3 px-4 font-medium text-slate-700">Feature</th>
|
||||
<th className="text-center py-3 px-4 font-medium text-slate-700">GitHub Actions</th>
|
||||
<th className="text-center py-3 px-4 font-medium text-slate-700">Lokaler Scheduler</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ComparisonRow
|
||||
feature="Taegliche Tests (07:00)"
|
||||
github={<span className="text-slate-600">schedule: cron</span>}
|
||||
local={<Badge color="emerald">macOS launchd</Badge>}
|
||||
/>
|
||||
<ComparisonRow
|
||||
feature="Push-basierte Tests"
|
||||
github={<span className="text-slate-600">on: push</span>}
|
||||
local={<Badge color="emerald">Git post-commit Hook</Badge>}
|
||||
/>
|
||||
<ComparisonRow
|
||||
feature="PR-basierte Tests"
|
||||
github={<Badge color="emerald">on: pull_request</Badge>}
|
||||
local={<Badge color="amber">Nicht moeglich</Badge>}
|
||||
/>
|
||||
<ComparisonRow
|
||||
feature="DSGVO-Konformitaet"
|
||||
github={<Badge color="amber">Daten bei GitHub (US)</Badge>}
|
||||
local={<Badge color="emerald">100% lokal</Badge>}
|
||||
/>
|
||||
<ComparisonRow
|
||||
feature="Offline-Faehig"
|
||||
github={<Badge color="red">Nein</Badge>}
|
||||
local={<Badge color="emerald">Ja</Badge>}
|
||||
isLast
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ComparisonRow({
|
||||
feature,
|
||||
github,
|
||||
local,
|
||||
isLast = false,
|
||||
}: {
|
||||
feature: string
|
||||
github: React.ReactNode
|
||||
local: React.ReactNode
|
||||
isLast?: boolean
|
||||
}) {
|
||||
return (
|
||||
<tr className={isLast ? '' : 'border-b border-slate-100'}>
|
||||
<td className="py-3 px-4 text-slate-600">{feature}</td>
|
||||
<td className="py-3 px-4 text-center">{github}</td>
|
||||
<td className="py-3 px-4 text-center">{local}</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
function Badge({ color, children }: { color: 'emerald' | 'amber' | 'red'; children: React.ReactNode }) {
|
||||
const colorClasses = {
|
||||
emerald: 'bg-emerald-100 text-emerald-700',
|
||||
amber: 'bg-amber-100 text-amber-700',
|
||||
red: 'bg-red-100 text-red-700',
|
||||
}
|
||||
return (
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${colorClasses[color]}`}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
function ConfigurationDetails() {
|
||||
return (
|
||||
<div className="bg-slate-50 rounded-lg p-4">
|
||||
<h3 className="font-medium text-slate-800 mb-4">Konfiguration</h3>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{/* launchd Configuration */}
|
||||
<div>
|
||||
<h4 className="font-medium text-slate-700 mb-3">launchd Job</h4>
|
||||
<div className="bg-slate-900 rounded-lg p-4 font-mono text-sm text-slate-100 overflow-x-auto">
|
||||
<pre>{`# ~/Library/LaunchAgents/com.breakpilot.bqas.plist
|
||||
Label: com.breakpilot.bqas
|
||||
Schedule: 07:00 taeglich
|
||||
Script: /voice-service/scripts/run_bqas.sh
|
||||
Logs: /var/log/bqas/`}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Environment Variables */}
|
||||
<div>
|
||||
<h4 className="font-medium text-slate-700 mb-3">Umgebungsvariablen</h4>
|
||||
<div className="space-y-2 text-sm">
|
||||
<EnvVar name="BQAS_SERVICE_URL" value="http://localhost:8091" />
|
||||
<EnvVar name="BQAS_REGRESSION_THRESHOLD" value="0.1" />
|
||||
<EnvVar name="BQAS_NOTIFY_DESKTOP" value="true" isActive />
|
||||
<EnvVar name="BQAS_NOTIFY_SLACK" value="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function EnvVar({ name, value, isActive }: { name: string; value: string; isActive?: boolean }) {
|
||||
return (
|
||||
<div className="flex justify-between p-2 bg-white rounded">
|
||||
<span className="font-mono text-slate-600">{name}</span>
|
||||
<span className={isActive ? 'text-emerald-600 font-medium' : value === 'false' ? 'text-slate-400' : 'text-slate-900'}>
|
||||
{value}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function DetailedExplanation() {
|
||||
return (
|
||||
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl border border-blue-200 p-6">
|
||||
<h3 className="text-lg font-semibold text-slate-900 mb-4 flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Detaillierte Erklaerung
|
||||
</h3>
|
||||
|
||||
<div className="prose prose-sm max-w-none text-slate-700">
|
||||
<h4 className="text-base font-semibold mt-4 mb-2">Warum ein lokaler Scheduler?</h4>
|
||||
<p className="mb-4">
|
||||
Der lokale BQAS Scheduler wurde entwickelt, um die gleiche Funktionalitaet wie GitHub Actions zu bieten,
|
||||
aber mit dem entscheidenden Vorteil, dass <strong>alle Daten zu 100% auf dem lokalen Mac Mini verbleiben</strong>.
|
||||
Dies ist besonders wichtig fuer DSGVO-Konformitaet, da keine Schuelerdaten oder Testergebnisse an externe Server uebertragen werden.
|
||||
</p>
|
||||
|
||||
<h4 className="text-base font-semibold mt-4 mb-2">Komponenten</h4>
|
||||
<ul className="list-disc list-inside space-y-2 mb-4">
|
||||
<li>
|
||||
<strong>run_bqas.sh</strong> - Hauptscript das pytest ausfuehrt, Regression-Checks macht und Benachrichtigungen versendet
|
||||
</li>
|
||||
<li>
|
||||
<strong>launchd Job</strong> - macOS-nativer Scheduler der das Script taeglich um 07:00 Uhr startet
|
||||
</li>
|
||||
<li>
|
||||
<strong>Git Hook</strong> - post-commit Hook der bei Aenderungen im voice-service automatisch Quick-Tests startet
|
||||
</li>
|
||||
<li>
|
||||
<strong>Notifier</strong> - Python-Modul das Desktop-, Slack- und E-Mail-Benachrichtigungen versendet
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 className="text-base font-semibold mt-4 mb-2">Installation</h4>
|
||||
<div className="bg-slate-900 rounded-lg p-3 font-mono text-sm text-slate-100 mb-4">
|
||||
<code>./voice-service/scripts/install_bqas_scheduler.sh install</code>
|
||||
</div>
|
||||
|
||||
<h4 className="text-base font-semibold mt-4 mb-2">Vorteile gegenueber GitHub Actions</h4>
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>100% DSGVO-konform - alle Daten bleiben lokal</li>
|
||||
<li>Keine Internet-Abhaengigkeit - funktioniert auch offline</li>
|
||||
<li>Keine GitHub-Kosten fuer private Repositories</li>
|
||||
<li>Schnellere Ausfuehrung ohne Cloud-Overhead</li>
|
||||
<li>Volle Kontrolle ueber Scheduling und Benachrichtigungen</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// SVG Icons
|
||||
// ============================================================================
|
||||
|
||||
function ClockIcon() {
|
||||
return (
|
||||
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function TerminalIcon() {
|
||||
return (
|
||||
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function BellIcon() {
|
||||
return (
|
||||
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user