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>
146 lines
6.9 KiB
TypeScript
146 lines
6.9 KiB
TypeScript
'use client'
|
|
|
|
import type { PipelineRun } from '../types'
|
|
|
|
interface PipelinesTabProps {
|
|
pipelineHistory: PipelineRun[]
|
|
triggeringPipeline: boolean
|
|
triggerPipeline: () => Promise<void>
|
|
}
|
|
|
|
export function PipelinesTab({
|
|
pipelineHistory,
|
|
triggeringPipeline,
|
|
triggerPipeline,
|
|
}: PipelinesTabProps) {
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Pipeline Controls */}
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-slate-800">Gitea Actions Pipelines</h3>
|
|
<p className="text-sm text-slate-600">Workflows werden bei Push auf main/develop automatisch ausgefuehrt</p>
|
|
</div>
|
|
<button
|
|
onClick={triggerPipeline}
|
|
disabled={triggeringPipeline}
|
|
className="px-4 py-2 bg-orange-600 text-white rounded-lg font-medium hover:bg-orange-700 disabled:opacity-50 transition-colors flex items-center gap-2"
|
|
>
|
|
{triggeringPipeline ? (
|
|
<>
|
|
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
|
Laeuft...
|
|
</>
|
|
) : (
|
|
<>
|
|
<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>
|
|
Pipeline starten
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Available Pipelines */}
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div className="bg-green-50 border border-green-200 rounded-lg p-4">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className="w-2 h-2 rounded-full bg-green-500"></span>
|
|
<span className="font-medium text-green-800">SBOM Pipeline</span>
|
|
</div>
|
|
<p className="text-sm text-green-700 mb-2">Generiert Software Bill of Materials</p>
|
|
<p className="text-xs text-green-600">5 Jobs: generate, scan, license, upload, summary</p>
|
|
</div>
|
|
<div className="bg-slate-50 border border-slate-200 rounded-lg p-4 opacity-60">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className="w-2 h-2 rounded-full bg-slate-400"></span>
|
|
<span className="font-medium text-slate-600">Test Pipeline</span>
|
|
</div>
|
|
<p className="text-sm text-slate-500 mb-2">Unit & Integration Tests</p>
|
|
<p className="text-xs text-slate-400">Geplant</p>
|
|
</div>
|
|
<div className="bg-slate-50 border border-slate-200 rounded-lg p-4 opacity-60">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className="w-2 h-2 rounded-full bg-slate-400"></span>
|
|
<span className="font-medium text-slate-600">Security Pipeline</span>
|
|
</div>
|
|
<p className="text-sm text-slate-500 mb-2">SAST, SCA, Secrets Scan</p>
|
|
<p className="text-xs text-slate-400">Geplant</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Pipeline History */}
|
|
<div className="bg-slate-50 rounded-lg p-4">
|
|
<h4 className="font-medium text-slate-800 mb-4">Pipeline Historie</h4>
|
|
{pipelineHistory.length === 0 ? (
|
|
<div className="text-center py-8 text-slate-500">
|
|
Keine Pipeline-Runs vorhanden. Starten Sie die erste Pipeline!
|
|
</div>
|
|
) : (
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full">
|
|
<thead>
|
|
<tr className="border-b border-slate-200">
|
|
<th className="text-left py-2 px-3 text-xs font-semibold text-slate-500 uppercase">Status</th>
|
|
<th className="text-left py-2 px-3 text-xs font-semibold text-slate-500 uppercase">Workflow</th>
|
|
<th className="text-left py-2 px-3 text-xs font-semibold text-slate-500 uppercase">Branch</th>
|
|
<th className="text-left py-2 px-3 text-xs font-semibold text-slate-500 uppercase">Commit</th>
|
|
<th className="text-left py-2 px-3 text-xs font-semibold text-slate-500 uppercase">Gestartet</th>
|
|
<th className="text-left py-2 px-3 text-xs font-semibold text-slate-500 uppercase">Dauer</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-slate-100">
|
|
{pipelineHistory.map((run) => (
|
|
<tr key={run.id} className="hover:bg-white">
|
|
<td className="py-2 px-3">
|
|
<span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium ${
|
|
run.status === 'success' ? 'bg-green-100 text-green-800' :
|
|
run.status === 'failed' ? 'bg-red-100 text-red-800' :
|
|
run.status === 'running' ? 'bg-yellow-100 text-yellow-800' : 'bg-slate-100 text-slate-600'
|
|
}`}>
|
|
<span className={`w-1.5 h-1.5 rounded-full ${
|
|
run.status === 'success' ? 'bg-green-500' :
|
|
run.status === 'failed' ? 'bg-red-500' :
|
|
run.status === 'running' ? 'bg-yellow-500 animate-pulse' : 'bg-slate-400'
|
|
}`}></span>
|
|
{run.status}
|
|
</span>
|
|
</td>
|
|
<td className="py-2 px-3 text-sm text-slate-900">{run.workflow || 'SBOM Pipeline'}</td>
|
|
<td className="py-2 px-3 text-sm text-slate-600">{run.branch}</td>
|
|
<td className="py-2 px-3 text-sm font-mono text-slate-500">{run.commit_sha.substring(0, 8)}</td>
|
|
<td className="py-2 px-3 text-sm text-slate-500">{new Date(run.started_at).toLocaleString('de-DE')}</td>
|
|
<td className="py-2 px-3 text-sm text-slate-500">
|
|
{run.duration_seconds ? `${run.duration_seconds}s` : '-'}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Pipeline Architecture */}
|
|
<div className="bg-slate-50 rounded-lg p-4">
|
|
<h4 className="font-medium text-slate-800 mb-3">SBOM Pipeline Architektur</h4>
|
|
<pre className="bg-slate-800 text-slate-100 p-4 rounded-lg overflow-x-auto text-sm">
|
|
{`Gitea Actions Pipeline (.gitea/workflows/sbom.yaml)
|
|
|
|
|
+-- 1. generate-sbom -> Syft generiert CycloneDX SBOM
|
|
|
|
|
+-- 2. vulnerability-scan -> Grype scannt auf CVEs
|
|
|
|
|
+-- 3. license-check -> Prueft GPL/AGPL Lizenzen
|
|
|
|
|
+-- 4. upload-dashboard -> POST /api/v1/security/sbom/upload
|
|
|
|
|
+-- 5. summary -> Job Summary generieren`}
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|