feat(web): add phased security rollout ladder
This commit is contained in:
@@ -44,6 +44,26 @@ const routeRoleItems = [
|
||||
{ key: 'awooopApprovals', href: '/awooop/approvals', route: 'AwoooP', icon: Lock, color: '#6f6d66' },
|
||||
] as const
|
||||
|
||||
const rolloutPhaseItems = [
|
||||
{ key: 'observe', phase: '01', state: '現在', icon: Radar, color: '#d97757' },
|
||||
{ key: 'evidence', phase: '02', state: '補證', icon: ClipboardCheck, color: '#1f7a4d' },
|
||||
{ key: 'humanReview', phase: '03', state: '人控', icon: CheckCircle2, color: '#1f7a4d' },
|
||||
{ key: 'runtimeGate', phase: '04', state: '批准後', icon: ShieldCheck, color: '#6f6d66' },
|
||||
{ key: 'tightening', phase: '05', state: '收斂', icon: Lock, color: '#6f6d66' },
|
||||
] as const
|
||||
|
||||
const rolloutBoundaries = [
|
||||
'security_compliance_rollout_phase_count=5',
|
||||
'security_compliance_rollout_current_phase=observe_first',
|
||||
'security_compliance_rollout_runtime_phase_enabled=false',
|
||||
'security_compliance_rollout_enforcement_enabled=false',
|
||||
'security_compliance_rollout_action_buttons_allowed=false',
|
||||
'runtime_execution_authorized=false',
|
||||
'active_runtime_gate_count=0',
|
||||
'action_buttons_allowed=false',
|
||||
'not_authorization=true',
|
||||
] as const
|
||||
|
||||
function SecurityComplianceFrontStage({ locale }: { locale: string }) {
|
||||
const t = useTranslations('securityCompliance.frontStage')
|
||||
const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const }
|
||||
@@ -167,6 +187,76 @@ function SecurityComplianceFrontStage({ locale }: { locale: string }) {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-testid="security-compliance-low-friction-rollout-ladder"
|
||||
style={{
|
||||
background: '#fff',
|
||||
border: '0.5px solid #eee9dd',
|
||||
borderRadius: 8,
|
||||
marginTop: 14,
|
||||
padding: 12,
|
||||
...textWrap,
|
||||
}}
|
||||
>
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<h2 style={{ fontSize: 14, margin: 0, color: '#141413' }}>{t('rolloutTitle')}</h2>
|
||||
<p style={{ fontSize: 11, color: '#6f6d66', lineHeight: 1.55, margin: '5px 0 0' }}>
|
||||
{t('rolloutSubtitle')}
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(152px, 1fr))', gap: 8 }}>
|
||||
{rolloutPhaseItems.map(item => {
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<div
|
||||
key={item.key}
|
||||
style={{
|
||||
display: 'grid',
|
||||
alignContent: 'start',
|
||||
gap: 6,
|
||||
minHeight: 128,
|
||||
border: '0.5px solid #e7e1d3',
|
||||
borderRadius: 8,
|
||||
padding: 10,
|
||||
background: '#fffdf8',
|
||||
...textWrap,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
|
||||
<span style={{ fontSize: 10, color: '#87867f' }}>{t('phaseLabel')} {item.phase}</span>
|
||||
<Icon size={15} color={item.color} />
|
||||
</div>
|
||||
<div style={{ fontSize: 18, lineHeight: 1, fontWeight: 700, color: item.color }}>{item.state}</div>
|
||||
<h3 style={{ fontSize: 13, lineHeight: 1.25, margin: 0, color: '#141413' }}>
|
||||
{t(`rolloutPhases.${item.key}.title` as never)}
|
||||
</h3>
|
||||
<p style={{ fontSize: 11, color: '#6f6d66', lineHeight: 1.45, margin: 0 }}>
|
||||
{t(`rolloutPhases.${item.key}.body` as never)}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(190px, 1fr))', gap: 6, marginTop: 10 }}>
|
||||
{rolloutBoundaries.map(boundary => (
|
||||
<code
|
||||
key={boundary}
|
||||
style={{
|
||||
background: '#f7f5ee',
|
||||
border: '0.5px solid #e7e1d3',
|
||||
borderRadius: 8,
|
||||
padding: '7px 9px',
|
||||
color: '#4f4c45',
|
||||
fontSize: 11,
|
||||
lineHeight: 1.45,
|
||||
...textWrap,
|
||||
}}
|
||||
>
|
||||
{boundary}
|
||||
</code>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user