mirror of
https://github.com/FunnyWolf/agentic-soc-platform.git
synced 2026-08-22 13:12:56 +02:00
Split web detail payloads from related data
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,38 +1,120 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.permissions import SAFE_METHODS
|
||||
|
||||
from apps.enrichments.models import Enrichment
|
||||
from .models import Alert
|
||||
|
||||
|
||||
class AlertSerializer(serializers.ModelSerializer):
|
||||
artifact_count = serializers.SerializerMethodField()
|
||||
enrichment_count = serializers.SerializerMethodField()
|
||||
class AlertDetailSerializer(serializers.ModelSerializer):
|
||||
case_id = serializers.CharField(source="case.id", read_only=True)
|
||||
case_readable_id = serializers.CharField(source="case.case_id", read_only=True)
|
||||
case_title = serializers.CharField(source="case.title", read_only=True)
|
||||
case_status = serializers.CharField(source="case.status", read_only=True)
|
||||
case_category = serializers.CharField(source="case.category", read_only=True)
|
||||
|
||||
def get_artifact_count(self, obj):
|
||||
request = self.context.get("request")
|
||||
if request is not None and request.method not in SAFE_METHODS:
|
||||
return obj.artifacts.count()
|
||||
|
||||
prefetched_artifacts = getattr(obj, "_prefetched_objects_cache", {}).get("artifacts")
|
||||
if prefetched_artifacts is not None:
|
||||
return len(prefetched_artifacts)
|
||||
|
||||
annotated_value = getattr(obj, "artifact_count", None)
|
||||
if annotated_value is not None:
|
||||
return annotated_value
|
||||
|
||||
return obj.artifacts.count()
|
||||
|
||||
def get_enrichment_count(self, obj):
|
||||
return Enrichment.objects.filter(alert=obj).count()
|
||||
|
||||
class Meta:
|
||||
model = Alert
|
||||
fields = "__all__"
|
||||
fields = (
|
||||
"id",
|
||||
"alert_id",
|
||||
"case",
|
||||
"case_id",
|
||||
"case_readable_id",
|
||||
"case_title",
|
||||
"case_status",
|
||||
"case_category",
|
||||
"title",
|
||||
"severity",
|
||||
"confidence",
|
||||
"impact",
|
||||
"disposition",
|
||||
"action",
|
||||
"labels",
|
||||
"desc",
|
||||
"first_seen_time",
|
||||
"last_seen_time",
|
||||
"rule_id",
|
||||
"rule_name",
|
||||
"correlation_uid",
|
||||
"src_url",
|
||||
"source_uid",
|
||||
"data_sources",
|
||||
"analytic_name",
|
||||
"analytic_type",
|
||||
"analytic_state",
|
||||
"analytic_desc",
|
||||
"tactic",
|
||||
"technique",
|
||||
"sub_technique",
|
||||
"mitigation",
|
||||
"product_category",
|
||||
"product_vendor",
|
||||
"product_name",
|
||||
"product_feature",
|
||||
"policy_name",
|
||||
"policy_type",
|
||||
"policy_desc",
|
||||
"risk_level",
|
||||
"status",
|
||||
"status_detail",
|
||||
"remediation",
|
||||
"unmapped",
|
||||
"raw_data",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
read_only_fields = ("id", "alert_id", "created_at", "updated_at")
|
||||
|
||||
|
||||
class AlertListSerializer(AlertDetailSerializer):
|
||||
artifact_count = serializers.IntegerField(read_only=True, default=0)
|
||||
enrichment_count = serializers.IntegerField(read_only=True, default=0)
|
||||
|
||||
class Meta(AlertDetailSerializer.Meta):
|
||||
fields = (
|
||||
"id",
|
||||
"alert_id",
|
||||
"case",
|
||||
"case_id",
|
||||
"case_readable_id",
|
||||
"case_title",
|
||||
"case_status",
|
||||
"case_category",
|
||||
"title",
|
||||
"severity",
|
||||
"confidence",
|
||||
"impact",
|
||||
"disposition",
|
||||
"action",
|
||||
"labels",
|
||||
"desc",
|
||||
"first_seen_time",
|
||||
"last_seen_time",
|
||||
"rule_id",
|
||||
"rule_name",
|
||||
"correlation_uid",
|
||||
"src_url",
|
||||
"source_uid",
|
||||
"data_sources",
|
||||
"analytic_name",
|
||||
"analytic_type",
|
||||
"analytic_state",
|
||||
"analytic_desc",
|
||||
"tactic",
|
||||
"technique",
|
||||
"sub_technique",
|
||||
"mitigation",
|
||||
"product_category",
|
||||
"product_vendor",
|
||||
"product_name",
|
||||
"product_feature",
|
||||
"policy_name",
|
||||
"policy_type",
|
||||
"policy_desc",
|
||||
"risk_level",
|
||||
"status",
|
||||
"status_detail",
|
||||
"remediation",
|
||||
"artifact_count",
|
||||
"enrichment_count",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.db.models import Count
|
||||
from django.db.models import Count, IntegerField, OuterRef, Subquery, Value
|
||||
from django.db.models.functions import Coalesce
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import viewsets, permissions
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
@@ -6,13 +7,14 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from apps.accounts.permissions import IsBusinessWriterOrReadOnly
|
||||
from apps.audit.mixins import AuditActorMixin
|
||||
from apps.common.advanced_filters import AdvancedFilterBackend
|
||||
from apps.enrichments.models import Enrichment
|
||||
from .models import Alert
|
||||
from .serializers import AlertSerializer
|
||||
from .serializers import AlertDetailSerializer, AlertListSerializer
|
||||
|
||||
|
||||
class AlertViewSet(AuditActorMixin, viewsets.ModelViewSet):
|
||||
queryset = Alert.objects.select_related("case").prefetch_related("artifacts").order_by("-created_at")
|
||||
serializer_class = AlertSerializer
|
||||
queryset = Alert.objects.select_related("case").order_by("-created_at")
|
||||
serializer_class = AlertDetailSerializer
|
||||
permission_classes = [permissions.IsAuthenticated, IsBusinessWriterOrReadOnly]
|
||||
lookup_field = "id"
|
||||
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter, AdvancedFilterBackend)
|
||||
@@ -85,11 +87,44 @@ class AlertViewSet(AuditActorMixin, viewsets.ModelViewSet):
|
||||
raw_ordering = self.request.query_params.get("ordering", "")
|
||||
return any(field.strip().lstrip("-") == "artifact_count" for field in raw_ordering.split(","))
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
def annotate_list_counts(self, queryset):
|
||||
if self.is_ordering_by_artifact_count():
|
||||
queryset = queryset.annotate(artifact_count=Count("artifacts", distinct=True))
|
||||
else:
|
||||
artifact_count = (
|
||||
Alert.artifacts.through.objects
|
||||
.filter(alert_id=OuterRef("pk"))
|
||||
.order_by()
|
||||
.values("alert_id")
|
||||
.annotate(count=Count("artifact_id"))
|
||||
.values("count")[:1]
|
||||
)
|
||||
queryset = queryset.annotate(
|
||||
artifact_count=Coalesce(Subquery(artifact_count, output_field=IntegerField()), Value(0))
|
||||
)
|
||||
|
||||
enrichment_count = (
|
||||
Enrichment.objects
|
||||
.filter(alert_id=OuterRef("pk"))
|
||||
.order_by()
|
||||
.values("alert_id")
|
||||
.annotate(count=Count("id"))
|
||||
.values("count")[:1]
|
||||
)
|
||||
return queryset.annotate(
|
||||
enrichment_count=Coalesce(Subquery(enrichment_count, output_field=IntegerField()), Value(0))
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
if self.action == "list":
|
||||
queryset = self.annotate_list_counts(queryset)
|
||||
artifact_id = self.request.query_params.get("artifacts")
|
||||
if artifact_id:
|
||||
queryset = queryset.filter(artifacts__id=artifact_id)
|
||||
return queryset
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "list":
|
||||
return AlertListSerializer
|
||||
return AlertDetailSerializer
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.enrichments.models import Enrichment
|
||||
from .models import Artifact
|
||||
|
||||
|
||||
class ArtifactSerializer(serializers.ModelSerializer):
|
||||
alert_count = serializers.SerializerMethodField()
|
||||
enrichment_count = serializers.SerializerMethodField()
|
||||
|
||||
def get_alert_count(self, obj):
|
||||
annotated_value = getattr(obj, "alert_count", None)
|
||||
if annotated_value is not None:
|
||||
return annotated_value
|
||||
return obj.alerts.count()
|
||||
|
||||
def get_enrichment_count(self, obj):
|
||||
return Enrichment.objects.filter(artifact=obj).count()
|
||||
|
||||
class ArtifactDetailSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Artifact
|
||||
fields = "__all__"
|
||||
fields = (
|
||||
"id",
|
||||
"artifact_id",
|
||||
"name",
|
||||
"type",
|
||||
"role",
|
||||
"value",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
read_only_fields = ("id", "artifact_id", "created_at", "updated_at")
|
||||
|
||||
|
||||
class ArtifactListSerializer(ArtifactDetailSerializer):
|
||||
alert_count = serializers.IntegerField(read_only=True, default=0)
|
||||
enrichment_count = serializers.IntegerField(read_only=True, default=0)
|
||||
|
||||
class Meta(ArtifactDetailSerializer.Meta):
|
||||
fields = (
|
||||
"id",
|
||||
"artifact_id",
|
||||
"name",
|
||||
"type",
|
||||
"role",
|
||||
"value",
|
||||
"alert_count",
|
||||
"enrichment_count",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
|
||||
@@ -7,13 +7,14 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from apps.accounts.permissions import IsBusinessWriterOrReadOnly
|
||||
from apps.audit.mixins import AuditActorMixin
|
||||
from apps.common.advanced_filters import AdvancedFilterBackend
|
||||
from apps.enrichments.models import Enrichment
|
||||
from .models import Artifact
|
||||
from .serializers import ArtifactSerializer
|
||||
from .serializers import ArtifactDetailSerializer, ArtifactListSerializer
|
||||
|
||||
|
||||
class ArtifactViewSet(AuditActorMixin, viewsets.ModelViewSet):
|
||||
queryset = Artifact.objects.order_by("-created_at")
|
||||
serializer_class = ArtifactSerializer
|
||||
serializer_class = ArtifactDetailSerializer
|
||||
permission_classes = [permissions.IsAuthenticated, IsBusinessWriterOrReadOnly]
|
||||
lookup_field = "id"
|
||||
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter, AdvancedFilterBackend)
|
||||
@@ -50,9 +51,29 @@ class ArtifactViewSet(AuditActorMixin, viewsets.ModelViewSet):
|
||||
alert_count=Coalesce(Subquery(alert_count, output_field=IntegerField()), Value(0))
|
||||
)
|
||||
|
||||
def annotate_enrichment_count(self, queryset):
|
||||
enrichment_count = (
|
||||
Enrichment.objects
|
||||
.filter(artifact_id=OuterRef("pk"))
|
||||
.order_by()
|
||||
.values("artifact_id")
|
||||
.annotate(count=Count("id"))
|
||||
.values("count")[:1]
|
||||
)
|
||||
return queryset.annotate(
|
||||
enrichment_count=Coalesce(Subquery(enrichment_count, output_field=IntegerField()), Value(0))
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.annotate_alert_count(super().get_queryset())
|
||||
queryset = super().get_queryset()
|
||||
if self.action == "list":
|
||||
queryset = self.annotate_enrichment_count(self.annotate_alert_count(queryset))
|
||||
alert_id = self.request.query_params.get("alerts")
|
||||
if alert_id:
|
||||
queryset = queryset.filter(alerts__id=alert_id)
|
||||
return queryset
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "list":
|
||||
return ArtifactListSerializer
|
||||
return ArtifactDetailSerializer
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
from django.utils import timezone
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.alerts.serializers import AlertSerializer
|
||||
from apps.enrichments.models import Enrichment
|
||||
from apps.inbox.notifications import notify_case_assignment
|
||||
from .models import Case, CaseStatus
|
||||
|
||||
|
||||
class CaseSerializer(serializers.ModelSerializer):
|
||||
alerts = AlertSerializer(many=True, read_only=True)
|
||||
alert_count = serializers.IntegerField(read_only=True, default=0)
|
||||
playbook_count = serializers.IntegerField(read_only=True, default=0)
|
||||
enrichment_count = serializers.SerializerMethodField()
|
||||
class CaseDetailSerializer(serializers.ModelSerializer):
|
||||
assignee_name = serializers.SerializerMethodField()
|
||||
first_alert_seen_time = serializers.SerializerMethodField()
|
||||
detection_time_seconds = serializers.SerializerMethodField()
|
||||
@@ -26,9 +20,6 @@ class CaseSerializer(serializers.ModelSerializer):
|
||||
def get_assignee_name(self, obj):
|
||||
return self._get_user_name(obj.assignee)
|
||||
|
||||
def get_enrichment_count(self, obj):
|
||||
return Enrichment.objects.filter(case=obj).count()
|
||||
|
||||
def _duration_seconds(self, start, end):
|
||||
if not start or not end:
|
||||
return None
|
||||
@@ -87,11 +78,77 @@ class CaseSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Case
|
||||
fields = "__all__"
|
||||
fields = (
|
||||
"id",
|
||||
"case_id",
|
||||
"title",
|
||||
"severity",
|
||||
"impact",
|
||||
"priority",
|
||||
"confidence",
|
||||
"description",
|
||||
"category",
|
||||
"tags",
|
||||
"status",
|
||||
"verdict",
|
||||
"summary",
|
||||
"assignee",
|
||||
"assignee_name",
|
||||
"acknowledged_time",
|
||||
"closed_time",
|
||||
"correlation_uid",
|
||||
"severity_ai",
|
||||
"confidence_ai",
|
||||
"impact_ai",
|
||||
"priority_ai",
|
||||
"verdict_ai",
|
||||
"first_alert_seen_time",
|
||||
"detection_time_seconds",
|
||||
"acknowledgement_time_seconds",
|
||||
"response_time_seconds",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
read_only_fields = ("id", "case_id", "created_at", "updated_at")
|
||||
|
||||
|
||||
class CaseListSerializer(CaseSerializer):
|
||||
class Meta(CaseSerializer.Meta):
|
||||
exclude = ("investigation_report_ai_json",)
|
||||
fields = None
|
||||
class CaseListSerializer(CaseDetailSerializer):
|
||||
alert_count = serializers.IntegerField(read_only=True, default=0)
|
||||
playbook_count = serializers.IntegerField(read_only=True, default=0)
|
||||
enrichment_count = serializers.IntegerField(read_only=True, default=0)
|
||||
|
||||
class Meta(CaseDetailSerializer.Meta):
|
||||
fields = (
|
||||
"id",
|
||||
"case_id",
|
||||
"title",
|
||||
"severity",
|
||||
"impact",
|
||||
"priority",
|
||||
"confidence",
|
||||
"description",
|
||||
"category",
|
||||
"tags",
|
||||
"status",
|
||||
"verdict",
|
||||
"summary",
|
||||
"assignee",
|
||||
"assignee_name",
|
||||
"acknowledged_time",
|
||||
"closed_time",
|
||||
"correlation_uid",
|
||||
"severity_ai",
|
||||
"confidence_ai",
|
||||
"impact_ai",
|
||||
"priority_ai",
|
||||
"verdict_ai",
|
||||
"alert_count",
|
||||
"playbook_count",
|
||||
"enrichment_count",
|
||||
"first_alert_seen_time",
|
||||
"detection_time_seconds",
|
||||
"acknowledgement_time_seconds",
|
||||
"response_time_seconds",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
|
||||
@@ -2,20 +2,24 @@ from django.db.models import Count, DateTimeField, IntegerField, Min, OuterRef,
|
||||
from django.db.models.functions import Coalesce
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import viewsets, permissions
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.response import Response
|
||||
|
||||
from apps.accounts.permissions import IsBusinessWriterOrReadOnly
|
||||
from apps.alerts.models import Alert
|
||||
from apps.audit.context import audit_actor
|
||||
from apps.audit.mixins import AuditActorMixin
|
||||
from apps.common.advanced_filters import AdvancedFilterBackend
|
||||
from apps.enrichments.models import Enrichment
|
||||
from apps.playbooks.models import Playbook
|
||||
from .models import Case
|
||||
from .serializers import CaseListSerializer, CaseSerializer
|
||||
from .serializers import CaseDetailSerializer, CaseListSerializer
|
||||
|
||||
|
||||
class CaseViewSet(AuditActorMixin, viewsets.ModelViewSet):
|
||||
queryset = Case.objects.select_related("assignee").order_by("-created_at")
|
||||
serializer_class = CaseSerializer
|
||||
serializer_class = CaseDetailSerializer
|
||||
permission_classes = [permissions.IsAuthenticated, IsBusinessWriterOrReadOnly]
|
||||
lookup_field = "id"
|
||||
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter, AdvancedFilterBackend)
|
||||
@@ -105,19 +109,54 @@ class CaseViewSet(AuditActorMixin, viewsets.ModelViewSet):
|
||||
.order_by("first_seen_time")
|
||||
.values("first_seen_time")[:1]
|
||||
)
|
||||
enrichment_count = (
|
||||
Enrichment.objects
|
||||
.filter(case_id=OuterRef("pk"))
|
||||
.order_by()
|
||||
.values("case_id")
|
||||
.annotate(count=Count("id"))
|
||||
.values("count")[:1]
|
||||
)
|
||||
return queryset.annotate(
|
||||
alert_count=Coalesce(Subquery(alert_count, output_field=IntegerField()), Value(0)),
|
||||
playbook_count=Coalesce(Subquery(playbook_count, output_field=IntegerField()), Value(0)),
|
||||
enrichment_count=Coalesce(Subquery(enrichment_count, output_field=IntegerField()), Value(0)),
|
||||
first_alert_seen_time=Subquery(first_alert_seen_time, output_field=DateTimeField()),
|
||||
)
|
||||
|
||||
def annotate_detail_metrics(self, queryset):
|
||||
first_alert_seen_time = (
|
||||
Alert.objects
|
||||
.filter(case_id=OuterRef("pk"), first_seen_time__isnull=False)
|
||||
.order_by("first_seen_time")
|
||||
.values("first_seen_time")[:1]
|
||||
)
|
||||
return queryset.annotate(
|
||||
first_alert_seen_time=Subquery(first_alert_seen_time, output_field=DateTimeField()),
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.annotate_list_metrics(super().get_queryset())
|
||||
if self.action == "list":
|
||||
return queryset.defer("investigation_report_ai_json")
|
||||
return queryset
|
||||
return self.annotate_list_metrics(super().get_queryset()).defer("investigation_report_ai_json")
|
||||
if self.action in {"retrieve", "update", "partial_update"}:
|
||||
return self.annotate_detail_metrics(super().get_queryset()).defer("investigation_report_ai_json")
|
||||
return super().get_queryset()
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "list":
|
||||
return CaseListSerializer
|
||||
return CaseSerializer
|
||||
return CaseDetailSerializer
|
||||
|
||||
@action(detail=True, methods=["get", "patch"], url_path="investigation")
|
||||
def investigation(self, request, *args, **kwargs):
|
||||
case = self.get_object()
|
||||
if request.method == "PATCH":
|
||||
value = request.data.get("investigation_report_ai_json", "")
|
||||
with audit_actor(request.user):
|
||||
case.investigation_report_ai_json = value
|
||||
case.save(update_fields=["investigation_report_ai_json", "updated_at"])
|
||||
return Response({
|
||||
"id": str(case.id),
|
||||
"case_id": case.case_id,
|
||||
"investigation_report_ai_json": case.investigation_report_ai_json,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {Alert, Button, Spin} from 'antd'
|
||||
import {ReloadOutlined} from '@ant-design/icons'
|
||||
import client from '../api/client'
|
||||
import InvestigationReportView from './InvestigationReportView'
|
||||
|
||||
interface CaseInvestigationViewProps {
|
||||
caseId: string
|
||||
}
|
||||
|
||||
interface CaseInvestigationResponse {
|
||||
investigation_report_ai_json: unknown
|
||||
}
|
||||
|
||||
function errorMessage(error: unknown) {
|
||||
const data = (error as { response?: { data?: unknown } }).response?.data
|
||||
if (typeof data === 'string') return data
|
||||
if (data && typeof data === 'object' && 'detail' in data) {
|
||||
return String((data as { detail?: unknown }).detail || 'Failed to load investigation report')
|
||||
}
|
||||
return 'Failed to load investigation report'
|
||||
}
|
||||
|
||||
export default function CaseInvestigationView({ caseId }: CaseInvestigationViewProps) {
|
||||
const [value, setValue] = useState<unknown>('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const requestIdRef = useRef(0)
|
||||
|
||||
const loadReport = useCallback(() => {
|
||||
if (!caseId) return
|
||||
const requestId = requestIdRef.current + 1
|
||||
requestIdRef.current = requestId
|
||||
setLoading(true)
|
||||
setError('')
|
||||
|
||||
client.get<CaseInvestigationResponse>(`/cases/${encodeURIComponent(caseId)}/investigation/`)
|
||||
.then(({ data }) => {
|
||||
if (requestId !== requestIdRef.current) return
|
||||
setValue(data.investigation_report_ai_json || '')
|
||||
})
|
||||
.catch((loadError) => {
|
||||
if (requestId !== requestIdRef.current) return
|
||||
setValue('')
|
||||
setError(errorMessage(loadError))
|
||||
})
|
||||
.finally(() => {
|
||||
if (requestId === requestIdRef.current) setLoading(false)
|
||||
})
|
||||
}, [caseId])
|
||||
|
||||
useEffect(() => {
|
||||
loadReport()
|
||||
return () => {
|
||||
requestIdRef.current += 1
|
||||
}
|
||||
}, [loadReport])
|
||||
|
||||
if (loading) return <Spin style={{ margin: 32 }} />
|
||||
if (error) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<Alert
|
||||
type="error"
|
||||
showIcon
|
||||
message={error}
|
||||
action={<Button size="small" icon={<ReloadOutlined />} onClick={loadReport}>Retry</Button>}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <InvestigationReportView value={value} />
|
||||
}
|
||||
@@ -14,10 +14,10 @@ import {BookOpenText, BrainCircuit, BriefcaseBusiness, Fingerprint, Siren, WandS
|
||||
import AlertBasicView from '../components/AlertBasicView'
|
||||
import ArtifactBasicView from '../components/ArtifactBasicView'
|
||||
import CaseBasicView from '../components/CaseBasicView'
|
||||
import CaseInvestigationView from '../components/CaseInvestigationView'
|
||||
import CaseKnowledgeView from '../components/CaseKnowledgeView'
|
||||
import CasePlaybookAction from '../components/CasePlaybookRunModal'
|
||||
import EnrichmentBasicView from '../components/EnrichmentBasicView'
|
||||
import InvestigationReportView from '../components/InvestigationReportView'
|
||||
import KnowledgeBasicView from '../components/KnowledgeBasicView'
|
||||
import OverflowTags from '../components/OverflowTags'
|
||||
import PlaybookBasicView from '../components/PlaybookBasicView'
|
||||
@@ -256,7 +256,7 @@ const emptyTabs = {
|
||||
key: 'investigation',
|
||||
label: 'Investigation',
|
||||
icon: <FileTextOutlined/>,
|
||||
render: (record: RecordRow) => <InvestigationReportView value={record.investigation_report_ai_json}/>,
|
||||
render: (record: RecordRow) => <CaseInvestigationView caseId={String(record.id || '')}/>,
|
||||
},
|
||||
],
|
||||
alert: [
|
||||
|
||||
Reference in New Issue
Block a user