Files
breakpilot-compliance/admin-compliance/app/sdk/workflow/_components/CompareView.tsx
T
Benjamin Admin 79ce12caf1
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / build-sha-integrity (push) Failing after 4s
CI / validate-canonical-controls (push) Successful in 10s
CI / loc-budget (push) Successful in 14s
CI / sbom-scan (push) Has been skipped
CI / test-python-backend (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m42s
CI / test-go (push) Has been skipped
CI / test-python-document-crawler (push) Has been skipped
feat(workflow): 5-Stage Lifecycle UI im Compliance Workflow-Editor
Erweitert Phase 1 (Backend 5-Stage Lifecycle, Migration 148) jetzt auch
im Frontend: Status-Pills, Buttons und Modal-Texte differenzieren nun
zwischen DSB- und Mandanten-Pruefung.

- WorkflowStatusBar zeigt 5 Schritte: draft -> review_internal ->
  review_client -> approved -> published, mit status-spezifischen
  Action-Buttons (Save/Submit, DSB-Freigabe, Mandant-Freigabe, Publish).
- ApprovalModal differenziert Mode 'approve-internal' / 'approve-client' /
  'reject' mit eigenen Titles und Button-Labels.
- useWorkflowActions ruft neue Endpoints /approve-internal und
  /approve-client (Backend Phase 1); approveVersion bleibt als
  Backward-Compat-Alias.
- page.tsx leitet Modal-Confirm an passende Action weiter und akzeptiert
  review_internal/review_client im draftVersion-Filter.
- _types.ts: Status-Union + STATUS_LABELS um beide Review-Stufen
  erweitert; alter 'review'-Wert bleibt fuer Bestandsdaten erhalten.
- CompareView, SplitViewEditor, HistoryPanel: Status-Rendering und neue
  Action-Labels (submitted_internal, approved_internal, approved_client).

LOC-Exception fuer admin-compliance/lib/sdk/types/sdk-steps.ts (525):
zentrale SDK-Step-Registry mit kanonischer Reihenfolge — splits wuerden
die globale seq-Garantie zerreissen.

[guardrail-change]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 10:15:32 +02:00

159 lines
5.7 KiB
TypeScript

'use client'
import { Version, STATUS_LABELS } from '../_types'
import type { ApprovalModalMode } from './ApprovalModal'
interface CompareViewProps {
currentVersion: Version | null
draftVersion: Version | null
editedContent: string
onClose: () => void
onSaveDraft: () => void
onSubmitForReview: () => void
onShowApprovalModal: (mode: ApprovalModalMode) => void
onPublishVersion: () => void
}
export default function CompareView({
currentVersion,
draftVersion,
editedContent,
onClose,
onSaveDraft,
onSubmitForReview,
onShowApprovalModal,
onPublishVersion,
}: CompareViewProps) {
return (
<div className="fixed inset-0 bg-slate-900 z-50 flex flex-col">
{/* Header */}
<div className="bg-slate-800 border-b border-slate-700 px-6 py-4 flex items-center justify-between">
<div className="flex items-center gap-4">
<h2 className="text-xl font-semibold text-white">Versionsvergleich</h2>
<span className="text-slate-400">
{currentVersion ? `v${currentVersion.version}` : 'Keine Version'}
<span className="mx-2 text-slate-600">vs</span>
{draftVersion ? `v${draftVersion.version}` : 'Neue Version'}
</span>
</div>
<button
onClick={onClose}
className="px-4 py-2 bg-slate-700 text-white rounded-lg hover:bg-slate-600"
>
Schliessen
</button>
</div>
{/* Compare Panels */}
<div className="flex-1 grid grid-cols-2 gap-1 bg-slate-700">
{/* Left: Published */}
<div className="bg-white flex flex-col">
<div className="bg-emerald-100 border-b border-emerald-200 px-4 py-2">
<span className="font-medium text-emerald-800">Veroeffentlichte Version</span>
{currentVersion && (
<span className="ml-2 text-emerald-600">v{currentVersion.version}</span>
)}
</div>
<div className="flex-1 overflow-y-auto p-6 prose prose-sm max-w-none">
{currentVersion ? (
<div dangerouslySetInnerHTML={{ __html: currentVersion.content }} />
) : (
<p className="text-slate-500 text-center py-12">Keine veroeffentlichte Version</p>
)}
</div>
</div>
{/* Right: Draft */}
<div className="bg-white flex flex-col">
<div
className={`border-b px-4 py-2 ${
draftVersion?.status === 'draft'
? 'bg-yellow-100 border-yellow-200'
: draftVersion?.status === 'review' || draftVersion?.status === 'review_internal'
? 'bg-blue-100 border-blue-200'
: draftVersion?.status === 'review_client'
? 'bg-indigo-100 border-indigo-200'
: draftVersion?.status === 'approved'
? 'bg-green-100 border-green-200'
: 'bg-slate-100 border-slate-200'
}`}
>
<span className="font-medium text-slate-800">
{draftVersion ? 'Aenderungsversion' : 'Neue Version'}
</span>
{draftVersion && (
<span className="ml-2 text-slate-600">
v{draftVersion.version} -{' '}
{STATUS_LABELS[draftVersion.status]?.label ?? draftVersion.status}
</span>
)}
</div>
<div className="flex-1 overflow-y-auto p-6 prose prose-sm max-w-none">
<div dangerouslySetInnerHTML={{ __html: editedContent || draftVersion?.content || '' }} />
</div>
</div>
</div>
{/* Footer with Actions */}
<div className="bg-slate-800 border-t border-slate-700 px-6 py-4 flex items-center justify-end gap-3">
{draftVersion?.status === 'draft' && (
<>
<button
onClick={() => { onClose(); onSaveDraft() }}
className="px-4 py-2 bg-slate-600 text-white rounded-lg hover:bg-slate-500"
>
Speichern
</button>
<button
onClick={() => { onClose(); onSubmitForReview() }}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-500"
>
Zur Pruefung einreichen
</button>
</>
)}
{draftVersion?.status === 'review_internal' && (
<>
<button
onClick={() => { onClose(); onShowApprovalModal('reject') }}
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-500"
>
Ablehnen
</button>
<button
onClick={() => { onClose(); onShowApprovalModal('approve-internal') }}
className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-500"
>
DSB-Freigabe Mandant
</button>
</>
)}
{draftVersion?.status === 'review_client' && (
<>
<button
onClick={() => { onClose(); onShowApprovalModal('reject') }}
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-500"
>
Ablehnen
</button>
<button
onClick={() => { onClose(); onShowApprovalModal('approve-client') }}
className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-500"
>
Mandanten-Freigabe
</button>
</>
)}
{draftVersion?.status === 'approved' && (
<button
onClick={() => { onClose(); onPublishVersion() }}
className="px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-500"
>
Veroeffentlichen
</button>
)}
</div>
</div>
)
}