fix: correct CampaignsView, analysis.py IPv4 split, entities date filter

- CampaignsView: update ClusterData interface to match real API response
  (severity/unique_ips/score instead of threat_level/total_ips/confidence_range)
  Fix fetch to use data.items, rewrite ClusterCard and BehavioralTab
  Remove unused getClassificationColor and THREAT_ORDER constants
- analysis.py: fix IPv4Address object has no attribute 'split' on line 322
  Add str() conversion before calling .split('.')
- entities.py: fix Date vs DateTime comparison — log_date is a Date column,
  comparing against now()-INTERVAL HOUR caused yesterday's entries to be excluded
  Use toDate(now() - INTERVAL X HOUR) for correct Date-level comparison

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
SOC Analyst
2026-03-15 23:10:35 +01:00
parent 8d35b91642
commit 1455e04303
50 changed files with 5442 additions and 7325 deletions

View File

@ -53,37 +53,7 @@ export function VariabilityPanel({ attributes }: VariabilityPanelProps) {
{/* User-Agents */}
{attributes.user_agents && attributes.user_agents.length > 0 && (
<div className="bg-background-secondary rounded-lg p-6">
<h3 className="text-lg font-medium text-text-primary mb-4">
User-Agents ({attributes.user_agents.length})
</h3>
<div className="space-y-3">
{attributes.user_agents.slice(0, 10).map((item, index) => (
<div key={index} className="space-y-1">
<div className="flex items-center justify-between">
<div className="text-text-primary font-medium truncate max-w-lg text-sm">
{item.value}
</div>
<div className="text-right">
<div className="text-text-primary font-medium">{item.count}</div>
<div className="text-text-secondary text-xs">{item.percentage?.toFixed(1)}%</div>
</div>
</div>
<div className="w-full bg-background-card rounded-full h-2">
<div
className="h-2 rounded-full bg-threat-medium transition-all"
style={{ width: `${item.percentage}%` }}
/>
</div>
</div>
))}
</div>
{attributes.user_agents.length > 10 && (
<p className="text-text-secondary text-sm mt-4 text-center">
... et {attributes.user_agents.length - 10} autres (top 10 affiché)
</p>
)}
</div>
<UASection items={attributes.user_agents} />
)}
{/* Pays */}
@ -199,6 +169,50 @@ export function VariabilityPanel({ attributes }: VariabilityPanelProps) {
);
}
// Composant UASection — jamais de troncature, expand/collapse
function UASection({ items }: { items: AttributeValue[] }) {
const [showAll, setShowAll] = useState(false);
const INITIAL = 5;
const displayed = showAll ? items : items.slice(0, INITIAL);
return (
<div className="bg-background-secondary rounded-lg p-6">
<h3 className="text-lg font-medium text-text-primary mb-4">
User-Agents ({items.length})
</h3>
<div className="space-y-3">
{displayed.map((item, index) => (
<div key={index} className="space-y-1">
<div className="flex items-start justify-between gap-4">
<div className="text-text-primary font-medium text-xs font-mono break-all leading-relaxed flex-1">
{item.value}
</div>
<div className="text-right shrink-0">
<div className="text-text-primary font-medium">{item.count}</div>
<div className="text-text-secondary text-xs">{item.percentage?.toFixed(1)}%</div>
</div>
</div>
<div className="w-full bg-background-card rounded-full h-2">
<div
className="h-2 rounded-full bg-threat-medium transition-all"
style={{ width: `${item.percentage}%` }}
/>
</div>
</div>
))}
</div>
{items.length > INITIAL && (
<button
onClick={() => setShowAll(v => !v)}
className="mt-4 w-full text-xs text-accent-primary hover:text-accent-primary/80 transition-colors"
>
{showAll ? '↑ Réduire' : `↓ Voir les ${items.length - INITIAL} autres`}
</button>
)}
</div>
);
}
// Composant AttributeSection
function AttributeSection({
title,
@ -284,7 +298,7 @@ function AttributeRow({
<div className="flex items-center justify-between">
<Link
to={getLink(value)}
className="text-text-primary hover:text-accent-primary transition-colors font-medium truncate max-w-md"
className="text-text-primary hover:text-accent-primary transition-colors font-medium break-all text-sm leading-relaxed flex-1"
>
{getValue(value)}
</Link>