fix(sdk): Align scope types with engine output + project isolation + optional block progress
Some checks failed
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 46s
CI/CD / test-python-backend-compliance (push) Successful in 42s
CI/CD / test-python-document-crawler (push) Successful in 29s
CI/CD / test-python-dsms-gateway (push) Successful in 25s
CI/CD / deploy-hetzner (push) Failing after 2s
Some checks failed
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 46s
CI/CD / test-python-backend-compliance (push) Successful in 42s
CI/CD / test-python-document-crawler (push) Successful in 29s
CI/CD / test-python-dsms-gateway (push) Successful in 25s
CI/CD / deploy-hetzner (push) Failing after 2s
Type alignment (root cause of client-side crash):
- RiskFlag: id/title/description → severity/category/message/recommendation
- ScopeGap: id/title/recommendation/relatedDocuments → gapType/currentState/targetState/effort
- NextAction: id/priority:number/effortDays → actionType/priority:string/estimatedEffort
- ScopeReasoning: details → factors + impact
- TriggeredHardTrigger: {rule: HardTriggerRule} → flat fields (ruleId, description, etc.)
- All UI components updated to match engine output shape
Project isolation:
- Scope localStorage key now includes projectId (prevents data leak between projects)
Optional block progress:
- Blocks with only optional questions now show green checkmark when any question answered
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -37,14 +37,31 @@ const TABS: { id: TabId; label: string; icon: string }[] = [
|
||||
export default function ComplianceScopePage() {
|
||||
const { state: sdkState, dispatch } = useSDK()
|
||||
|
||||
// Project-specific storage key
|
||||
const projectStorageKey = sdkState.projectId
|
||||
? `${STORAGE_KEY}_${sdkState.projectId}`
|
||||
: STORAGE_KEY
|
||||
|
||||
// Active tab state
|
||||
const [activeTab, setActiveTab] = useState<TabId>('overview')
|
||||
|
||||
// Migrate old decision format: drop decision if it has old-format fields
|
||||
const migrateState = (state: ComplianceScopeState): ComplianceScopeState => {
|
||||
if (state.decision) {
|
||||
const d = state.decision as Record<string, unknown>
|
||||
// Old format had 'level' instead of 'determinedLevel', or docs with 'isMandatory'
|
||||
if (d.level || !d.determinedLevel) {
|
||||
return { ...state, decision: null }
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// Local scope state
|
||||
const [scopeState, setScopeState] = useState<ComplianceScopeState>(() => {
|
||||
// Try to load from SDK context first
|
||||
if (sdkState.complianceScope) {
|
||||
return sdkState.complianceScope
|
||||
return migrateState(sdkState.complianceScope)
|
||||
}
|
||||
return createEmptyScopeState()
|
||||
})
|
||||
@@ -68,14 +85,14 @@ export default function ComplianceScopePage() {
|
||||
const ctxScope = sdkState.complianceScope
|
||||
if (ctxScope && ctxScope.answers?.length > 0) {
|
||||
syncingFromSdk.current = true
|
||||
setScopeState(ctxScope)
|
||||
setScopeState(migrateState(ctxScope))
|
||||
setIsLoading(false)
|
||||
} else if (isLoading) {
|
||||
// SDK has no scope data — try localStorage fallback, then give up
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY)
|
||||
const stored = localStorage.getItem(projectStorageKey)
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored) as ComplianceScopeState
|
||||
const parsed = migrateState(JSON.parse(stored) as ComplianceScopeState)
|
||||
if (parsed.answers?.length > 0) {
|
||||
setScopeState(parsed)
|
||||
dispatch({ type: 'SET_COMPLIANCE_SCOPE', payload: parsed })
|
||||
@@ -106,7 +123,7 @@ export default function ComplianceScopePage() {
|
||||
return
|
||||
}
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(scopeState))
|
||||
localStorage.setItem(projectStorageKey, JSON.stringify(scopeState))
|
||||
dispatch({ type: 'SET_COMPLIANCE_SCOPE', payload: scopeState })
|
||||
} catch (error) {
|
||||
console.error('Failed to save compliance scope state:', error)
|
||||
@@ -194,7 +211,7 @@ export default function ComplianceScopePage() {
|
||||
const emptyState = createEmptyScopeState()
|
||||
setScopeState(emptyState)
|
||||
setActiveTab('overview')
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
localStorage.removeItem(projectStorageKey)
|
||||
}, [])
|
||||
|
||||
// Calculate completion statistics
|
||||
|
||||
Reference in New Issue
Block a user