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>
193 lines
8.7 KiB
TypeScript
193 lines
8.7 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* CI/CD Dashboard
|
|
*
|
|
* Zentrale Uebersicht fuer:
|
|
* - Gitea Actions Pipelines
|
|
* - Runner Status
|
|
* - Container Deployments
|
|
* - Pipeline Konfiguration
|
|
*/
|
|
|
|
import { PagePurpose } from '@/components/common/PagePurpose'
|
|
import { DevOpsPipelineSidebarResponsive } from '@/components/infrastructure/DevOpsPipelineSidebar'
|
|
import { useCiCdData } from './useCiCdData'
|
|
import type { TabType } from './types'
|
|
import { OverviewTab } from './_components/OverviewTab'
|
|
import { WoodpeckerTab } from './_components/WoodpeckerTab'
|
|
import { PipelinesTab } from './_components/PipelinesTab'
|
|
import { DeploymentsTab } from './_components/DeploymentsTab'
|
|
import { SetupTab } from './_components/SetupTab'
|
|
import { SchedulerTab } from './_components/SchedulerTab'
|
|
|
|
// ============================================================================
|
|
// Tab Definitions
|
|
// ============================================================================
|
|
|
|
const TABS: { id: TabType; name: string; icon: React.ReactNode }[] = [
|
|
{ id: 'overview', name: 'Uebersicht', icon: (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
</svg>
|
|
)},
|
|
{ id: 'woodpecker', name: 'Woodpecker CI', icon: (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} 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>
|
|
)},
|
|
{ id: 'pipelines', name: 'Gitea Pipelines', icon: (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
</svg>
|
|
)},
|
|
{ id: 'deployments', name: 'Deployments', icon: (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2" />
|
|
</svg>
|
|
)},
|
|
{ id: 'setup', name: 'Konfiguration', icon: (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
</svg>
|
|
)},
|
|
{ id: 'scheduler', name: 'BQAS Scheduler', icon: (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
)},
|
|
]
|
|
|
|
// ============================================================================
|
|
// Main Component
|
|
// ============================================================================
|
|
|
|
export default function CICDPage() {
|
|
const data = useCiCdData()
|
|
|
|
return (
|
|
<div>
|
|
<PagePurpose
|
|
title="CI/CD Dashboard"
|
|
purpose="Zentrale Uebersicht fuer Gitea Actions Pipelines, Runner-Status und Container-Deployments. Starten Sie Pipelines manuell und verwalten Sie Docker-Container."
|
|
audience={['DevOps', 'Entwickler']}
|
|
architecture={{
|
|
services: ['Gitea Actions', 'act_runner', 'Docker'],
|
|
databases: [],
|
|
}}
|
|
relatedPages={[
|
|
{ name: 'SBOM', href: '/infrastructure/sbom', description: 'Software Bill of Materials' },
|
|
{ name: 'Security', href: '/infrastructure/security', description: 'DevSecOps Dashboard' },
|
|
{ name: 'Test Quality', href: '/ai/test-quality', description: 'BQAS Test Dashboard' },
|
|
]}
|
|
collapsible={true}
|
|
defaultCollapsed={true}
|
|
/>
|
|
|
|
<DevOpsPipelineSidebarResponsive currentTool="ci-cd" />
|
|
|
|
{/* Messages */}
|
|
{data.error && (
|
|
<div className="bg-red-50 border border-red-200 rounded-xl p-4 mb-6">
|
|
<div className="flex items-center gap-2 text-red-800">
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<span className="font-medium">{data.error}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{data.message && (
|
|
<div className="bg-green-50 border border-green-200 rounded-xl p-4 mb-6">
|
|
<div className="flex items-center gap-2 text-green-800">
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
<span className="font-medium">{data.message}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Main Content */}
|
|
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
|
{/* Tabs */}
|
|
<div className="flex border-b border-slate-200">
|
|
<nav className="flex">
|
|
{TABS.map((tab) => (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => data.setActiveTab(tab.id)}
|
|
className={`px-6 py-4 text-sm font-medium border-b-2 transition-colors flex items-center gap-2 ${
|
|
data.activeTab === tab.id
|
|
? 'border-orange-500 text-orange-600'
|
|
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
|
}`}
|
|
>
|
|
{tab.icon}
|
|
{tab.name}
|
|
</button>
|
|
))}
|
|
</nav>
|
|
</div>
|
|
|
|
{/* Tab Content */}
|
|
<div className="p-6">
|
|
{data.loading ? (
|
|
<div className="flex justify-center py-12">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-orange-600" />
|
|
</div>
|
|
) : (
|
|
<>
|
|
{data.activeTab === 'overview' && (
|
|
<OverviewTab
|
|
pipelineStatus={data.pipelineStatus}
|
|
pipelineHistory={data.pipelineHistory}
|
|
systemStats={data.systemStats}
|
|
dockerStats={data.dockerStats}
|
|
woodpeckerStatus={data.woodpeckerStatus}
|
|
triggeringWoodpecker={data.triggeringWoodpecker}
|
|
triggerWoodpeckerPipeline={data.triggerWoodpeckerPipeline}
|
|
setActiveTab={data.setActiveTab}
|
|
/>
|
|
)}
|
|
{data.activeTab === 'woodpecker' && (
|
|
<WoodpeckerTab
|
|
woodpeckerStatus={data.woodpeckerStatus}
|
|
triggeringWoodpecker={data.triggeringWoodpecker}
|
|
triggerWoodpeckerPipeline={data.triggerWoodpeckerPipeline}
|
|
/>
|
|
)}
|
|
{data.activeTab === 'pipelines' && (
|
|
<PipelinesTab
|
|
pipelineHistory={data.pipelineHistory}
|
|
triggeringPipeline={data.triggeringPipeline}
|
|
triggerPipeline={data.triggerPipeline}
|
|
/>
|
|
)}
|
|
{data.activeTab === 'deployments' && (
|
|
<DeploymentsTab
|
|
dockerStats={data.dockerStats}
|
|
filteredContainers={data.filteredContainers}
|
|
containerFilter={data.containerFilter}
|
|
setContainerFilter={data.setContainerFilter}
|
|
actionLoading={data.actionLoading}
|
|
containerAction={data.containerAction}
|
|
loadContainerData={data.loadContainerData}
|
|
/>
|
|
)}
|
|
{data.activeTab === 'setup' && (
|
|
<SetupTab pipelineStatus={data.pipelineStatus} />
|
|
)}
|
|
{data.activeTab === 'scheduler' && (
|
|
<SchedulerTab />
|
|
)}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|