fix(web): connect alerts to incident evidence chain
This commit is contained in:
@@ -19,8 +19,10 @@ import type { IncidentResponse, DecisionInfo, IncidentTimelineResponse } from '@
|
||||
import { apiClient } from '@/lib/api-client'
|
||||
import { CURRENT_USER } from '@/lib/constants'
|
||||
import { useCSRF } from '@/hooks/useCSRF'
|
||||
import { Link } from '@/i18n/routing'
|
||||
import { FlowPipeline, type FlowStage } from './flow-pipeline'
|
||||
import type { AwoooPStatusChain } from '@/components/awooop/status-chain'
|
||||
import { Activity, GitBranch, Lightbulb, ListChecks, Monitor, ShieldCheck } from 'lucide-react'
|
||||
|
||||
// =============================================================================
|
||||
// Types
|
||||
@@ -34,6 +36,7 @@ export interface IncidentCardProps {
|
||||
incident: IncidentResponse
|
||||
decision?: DecisionInfo | null
|
||||
statusChain?: AwoooPStatusChain | null
|
||||
projectId?: string
|
||||
onApprovalChange?: (proposalId: string, newStatus: 'approved' | 'rejected') => void
|
||||
}
|
||||
|
||||
@@ -286,7 +289,7 @@ function useApprovalAction(
|
||||
// Component
|
||||
// =============================================================================
|
||||
|
||||
export function IncidentCard({ incident, decision, statusChain, onApprovalChange }: IncidentCardProps) {
|
||||
export function IncidentCard({ incident, decision, statusChain, projectId = 'awoooi', onApprovalChange }: IncidentCardProps) {
|
||||
const t = useTranslations('incident.card')
|
||||
const { csrfToken } = useCSRF()
|
||||
|
||||
@@ -428,6 +431,40 @@ export function IncidentCard({ incident, decision, statusChain, onApprovalChange
|
||||
latest: latestSource,
|
||||
})
|
||||
: null
|
||||
const encodedProjectId = encodeURIComponent(projectId)
|
||||
const encodedIncidentId = encodeURIComponent(incident.incident_id)
|
||||
const truthLinks = [
|
||||
{
|
||||
key: 'monitoring',
|
||||
label: t('truthLinkMonitoring'),
|
||||
href: `/monitoring?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
|
||||
Icon: Monitor,
|
||||
},
|
||||
{
|
||||
key: 'workItems',
|
||||
label: t('truthLinkWorkItems'),
|
||||
href: `/awooop/work-items?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
|
||||
Icon: ListChecks,
|
||||
},
|
||||
{
|
||||
key: 'runs',
|
||||
label: t('truthLinkRuns'),
|
||||
href: `/awooop/runs?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
|
||||
Icon: Activity,
|
||||
},
|
||||
{
|
||||
key: 'approvals',
|
||||
label: t('truthLinkApprovals'),
|
||||
href: `/awooop/approvals?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
|
||||
Icon: ShieldCheck,
|
||||
},
|
||||
{
|
||||
key: 'tickets',
|
||||
label: t('truthLinkTickets'),
|
||||
href: `/tickets?project_id=${encodedProjectId}&incident_id=${encodedIncidentId}` as never,
|
||||
Icon: GitBranch,
|
||||
},
|
||||
]
|
||||
|
||||
const serviceName = incident.affected_services?.[0] ?? '--'
|
||||
const duration = formatDuration(incident.created_at)
|
||||
@@ -738,6 +775,44 @@ export function IncidentCard({ incident, decision, statusChain, onApprovalChange
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
margin: '0 14px 10px',
|
||||
padding: '7px 9px',
|
||||
border: '0.5px solid #e0ddd4',
|
||||
borderRadius: 6,
|
||||
background: '#fff',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 7,
|
||||
flexWrap: 'wrap',
|
||||
}}>
|
||||
<span style={{ fontSize: 11, color: '#87867f', fontWeight: 700 }}>
|
||||
{t('truthLinksLabel')}
|
||||
</span>
|
||||
{truthLinks.map(({ key, label, href, Icon }) => (
|
||||
<Link
|
||||
key={key}
|
||||
href={href}
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
padding: '3px 7px',
|
||||
border: '0.5px solid #d8d3c7',
|
||||
borderRadius: 5,
|
||||
background: '#faf9f3',
|
||||
color: '#3f3a32',
|
||||
fontSize: 11,
|
||||
fontWeight: 600,
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
>
|
||||
<Icon aria-hidden="true" size={12} strokeWidth={1.8} />
|
||||
{label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleTimelineToggle}
|
||||
style={{
|
||||
@@ -954,8 +1029,9 @@ export function IncidentCard({ incident, decision, statusChain, onApprovalChange
|
||||
}}>
|
||||
<div style={{ color: '#141413', marginBottom: 4 }}>{decisionAction}</div>
|
||||
{decisionReasoning && (
|
||||
<div style={{ color: '#87867f', fontStyle: 'italic' }}>
|
||||
💡 {decisionReasoning.slice(0, 150)}{decisionReasoning.length > 150 ? '...' : ''}
|
||||
<div style={{ color: '#87867f', fontStyle: 'italic', display: 'flex', alignItems: 'flex-start', gap: 5 }}>
|
||||
<Lightbulb aria-hidden="true" size={14} strokeWidth={1.8} style={{ flexShrink: 0, marginTop: 1 }} />
|
||||
<span>{decisionReasoning.slice(0, 150)}{decisionReasoning.length > 150 ? '...' : ''}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user