feat(cra): hard CRA<->IACE link — IACE tab pulls the linked assessment [migration-approved]
Migration 153 adds compliance_cra_projects.linked_iace_project_id (additive,
idempotent). New thin router cra_link_routes.py: POST /projects/{id}/link-iace
sets the reference; GET /by-iace/{iace_project_id} returns the linked CRA project
+ its latest assessment snapshot. The IACE "CRA / Cyber" tab now resolves the
linked CRA assessment first (real, from the snapshot) and only falls back to the
demo scenario when nothing is linked. One assessment, two views.
[migration-approved] — user approved the new column for the CRA<->IACE reference.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -102,17 +102,36 @@ export function useCRA(projectId?: string) {
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
fetch('/api/v1/cra/assess', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(buildPayload()),
|
||||
})
|
||||
.then((r) => (r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`))))
|
||||
.then((j) => { if (!cancelled) { setData(merge(j)); setLive(true) } })
|
||||
.catch((err) => {
|
||||
;(async () => {
|
||||
// 1. Is a CRA project LINKED to this IACE project? Then show its real
|
||||
// assessment (latest snapshot) instead of the demo scenario.
|
||||
if (projectId) {
|
||||
try {
|
||||
const lr = await fetch(`/api/v1/cra/by-iace/${projectId}`)
|
||||
if (lr.ok) {
|
||||
const link = await lr.json()
|
||||
if (link?.linked && link.assessment) {
|
||||
if (!cancelled) { setData(merge(link.assessment)); setLive(true) }
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch { /* fall through to the demo assess */ }
|
||||
}
|
||||
// 2. Fallback: live demo assess (scenario findings).
|
||||
try {
|
||||
const r = await fetch('/api/v1/cra/assess', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(buildPayload()),
|
||||
})
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`)
|
||||
const j = await r.json()
|
||||
if (!cancelled) { setData(merge(j)); setLive(true) }
|
||||
} catch (err) {
|
||||
console.error('CRA assess fetch failed, using static scenario:', err)
|
||||
if (!cancelled) { setData(DEMO_SCENARIO); setLive(false) }
|
||||
})
|
||||
}
|
||||
})()
|
||||
return () => { cancelled = true }
|
||||
}, [buildPayload])
|
||||
}, [buildPayload, projectId])
|
||||
|
||||
const refreshSnapshots = useCallback(() => {
|
||||
if (!projectId) return
|
||||
|
||||
Reference in New Issue
Block a user