feat(iace): KI-Vorschlag Button im FMEA-Tab
Build + Deploy / build-admin-compliance (push) Successful in 16s
Build + Deploy / build-backend-compliance (push) Successful in 24s
Build + Deploy / build-ai-sdk (push) Successful in 12s
Build + Deploy / build-developer-portal (push) Successful in 12s
Build + Deploy / build-tts (push) Successful in 34s
Build + Deploy / build-document-crawler (push) Successful in 11s
Build + Deploy / build-dsms-gateway (push) Successful in 11s
Build + Deploy / build-dsms-node (push) Successful in 14s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 16s
CI / secret-scan (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 2m49s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 43s
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 26s
CI / test-python-dsms-gateway (push) Successful in 23s
CI / validate-canonical-controls (push) Successful in 13s
Build + Deploy / trigger-orca (push) Successful in 2m25s
Build + Deploy / build-admin-compliance (push) Successful in 16s
Build + Deploy / build-backend-compliance (push) Successful in 24s
Build + Deploy / build-ai-sdk (push) Successful in 12s
Build + Deploy / build-developer-portal (push) Successful in 12s
Build + Deploy / build-tts (push) Successful in 34s
Build + Deploy / build-document-crawler (push) Successful in 11s
Build + Deploy / build-dsms-gateway (push) Successful in 11s
Build + Deploy / build-dsms-node (push) Successful in 14s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 16s
CI / secret-scan (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 2m49s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 43s
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 26s
CI / test-python-dsms-gateway (push) Successful in 23s
CI / validate-canonical-controls (push) Successful in 13s
Build + Deploy / trigger-orca (push) Successful in 2m25s
- Dropdown: Komponente waehlen → "KI-Vorschlag" klicken - Ruft POST /projects/:id/components/:cid/suggest-fms auf - Zeigt LLM-generierte oder Bibliotheks-FMs als Overlay - Jeder Vorschlag mit Name, Auswirkung, S/O/D, RPZ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,5 +130,31 @@ export function useFMEA(projectId: string) {
|
||||
acceptable: rows.filter((r) => r.rpz <= 100).length,
|
||||
}
|
||||
|
||||
return { rows, loading, stats }
|
||||
const [suggesting, setSuggesting] = useState(false)
|
||||
const [suggestions, setSuggestions] = useState<FailureMode[]>([])
|
||||
const [suggestSource, setSuggestSource] = useState<string>('')
|
||||
|
||||
async function suggestFMs(componentId: string) {
|
||||
setSuggesting(true)
|
||||
setSuggestions([])
|
||||
try {
|
||||
const res = await fetch(`/api/sdk/v1/iace/projects/${projectId}/components/${componentId}/suggest-fms`, {
|
||||
method: 'POST',
|
||||
})
|
||||
if (res.ok) {
|
||||
const json = await res.json()
|
||||
setSuggestions(json.suggestions || [])
|
||||
setSuggestSource(json.source || 'unknown')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('FM suggest failed:', err)
|
||||
} finally {
|
||||
setSuggesting(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Get unique components for the suggest button
|
||||
const components = [...new Map(rows.map((r) => [r.component.id, r.component])).values()]
|
||||
|
||||
return { rows, loading, stats, components, suggestFMs, suggesting, suggestions, suggestSource, setSuggestions }
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ function rpzLabel(rpz: number): string {
|
||||
|
||||
export default function FMEAPage() {
|
||||
const { projectId } = useParams<{ projectId: string }>()
|
||||
const { rows, loading, stats } = useFMEA(projectId)
|
||||
const { rows, loading, stats, components, suggestFMs, suggesting, suggestions, suggestSource, setSuggestions } = useFMEA(projectId)
|
||||
const [suggestComp, setSuggestComp] = useState<string | null>(null)
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
@@ -50,7 +51,34 @@ export default function FMEAPage() {
|
||||
{/* Info Box */}
|
||||
<FMEAInfoBox />
|
||||
|
||||
{/* Export Button */}
|
||||
{/* KI-Vorschlag + Export */}
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
value={suggestComp || ''}
|
||||
onChange={(e) => setSuggestComp(e.target.value || null)}
|
||||
className="px-3 py-2 border border-gray-300 rounded-lg text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-white"
|
||||
>
|
||||
<option value="">Komponente waehlen...</option>
|
||||
{components.map((c) => (
|
||||
<option key={c.id} value={c.id}>{c.name}</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
onClick={() => suggestComp && suggestFMs(suggestComp)}
|
||||
disabled={!suggestComp || suggesting}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 text-sm font-medium transition-colors disabled:opacity-50"
|
||||
>
|
||||
{suggesting ? (
|
||||
<span className="animate-spin inline-block w-4 h-4 border-2 border-white border-t-transparent rounded-full" />
|
||||
) : (
|
||||
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
|
||||
</svg>
|
||||
)}
|
||||
KI-Vorschlag
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<a
|
||||
href={`/api/sdk/v1/iace/projects/${projectId}/fmea/export`}
|
||||
@@ -63,6 +91,35 @@ export default function FMEAPage() {
|
||||
VDA Excel exportieren
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Suggest Results */}
|
||||
{suggestions.length > 0 && (
|
||||
<div className="bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800 rounded-xl p-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-semibold text-purple-800 dark:text-purple-300">
|
||||
KI-Vorschlaege ({suggestions.length}) — {suggestSource === 'llm' ? 'LLM-generiert' : 'Bibliothek'}
|
||||
</h3>
|
||||
<button onClick={() => setSuggestions([])} className="text-xs text-purple-600 hover:text-purple-800">Schliessen</button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{suggestions.map((fm, i) => (
|
||||
<div key={i} className="flex items-center justify-between bg-white dark:bg-gray-800 rounded-lg p-3 border border-purple-100 dark:border-purple-800">
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-sm font-medium text-gray-900 dark:text-white">{fm.name_de}</div>
|
||||
<div className="text-xs text-gray-500 mt-0.5">{fm.effect}</div>
|
||||
<div className="flex gap-3 mt-1 text-xs text-gray-400">
|
||||
<span>S={fm.default_severity}</span>
|
||||
<span>O={fm.default_occurrence}</span>
|
||||
<span>D={fm.default_detection}</span>
|
||||
<span className="font-bold">RPZ={fm.default_severity * fm.default_occurrence * fm.default_detection}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
|
||||
Reference in New Issue
Block a user