200 lines
6.1 KiB
Plaintext
200 lines
6.1 KiB
Plaintext
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1><%= @project.name %> - Analytics</h1>
|
|
<div>
|
|
<%= link_to "← Back to Project", project_path(@project), class: "btn btn-secondary" %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Time Range Selector -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5>Time Range</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<%= form_with url: analytics_project_path(@project), method: :get, local: true do |form| %>
|
|
<div class="row align-items-end">
|
|
<div class="col-md-6">
|
|
<%= form.label :time_range, "Time Range", class: "form-label" %>
|
|
<%= form.select :time_range,
|
|
options_for_select([
|
|
["Last Hour", 1],
|
|
["Last 6 Hours", 6],
|
|
["Last 24 Hours", 24],
|
|
["Last 7 Days", 168],
|
|
["Last 30 Days", 720]
|
|
], @time_range),
|
|
{}, class: "form-select" %>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<%= form.submit "Update", class: "btn btn-primary" %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary Stats -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-4">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<h3 class="text-primary"><%= number_with_delimiter(@total_events) %></h3>
|
|
<p class="card-text">Total Events</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<h3 class="text-success"><%= number_with_delimiter(@allowed_events) %></h3>
|
|
<p class="card-text">Allowed</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<h3 class="text-danger"><%= number_with_delimiter(@blocked_events) %></h3>
|
|
<p class="card-text">Blocked</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Top Blocked IPs -->
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Top Blocked IPs</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<% if @top_blocked_ips.any? %>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>IP Address</th>
|
|
<th>Blocked Count</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% @top_blocked_ips.each do |stat| %>
|
|
<tr>
|
|
<td><code><%= stat.ip_address %></code></td>
|
|
<td><%= number_with_delimiter(stat.count) %></td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% else %>
|
|
<p class="text-muted">No blocked events in this time range.</p>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Country Distribution -->
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Top Countries</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<% if @country_stats.any? %>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Country</th>
|
|
<th>Events</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% @country_stats.each do |stat| %>
|
|
<tr>
|
|
<td><%= stat.country_code || 'Unknown' %></td>
|
|
<td><%= number_with_delimiter(stat.count) %></td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% else %>
|
|
<p class="text-muted">No country data available.</p>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Distribution -->
|
|
<div class="row mt-4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Action Distribution</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<% if @action_stats.any? %>
|
|
<div class="row">
|
|
<% @action_stats.each do |stat| %>
|
|
<div class="col-md-3 text-center mb-3">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h4><%= stat.action.upcase %></h4>
|
|
<p class="card-text">
|
|
<span class="badge bg-<%=
|
|
case stat.action
|
|
when 'allow', 'pass' then 'success'
|
|
when 'block', 'deny' then 'danger'
|
|
when 'challenge' then 'warning'
|
|
when 'rate_limit' then 'info'
|
|
else 'secondary'
|
|
end %>">
|
|
<%= number_with_delimiter(stat.count) %>
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% else %>
|
|
<p class="text-muted">No action data available.</p>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<% if @total_events > 0 %>
|
|
<div class="row mt-4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Block Rate</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="progress" style="height: 30px;">
|
|
<% blocked_percentage = (@blocked_events.to_f / @total_events * 100).round(1) %>
|
|
<% allowed_percentage = (@allowed_events.to_f / @total_events * 100).round(1) %>
|
|
|
|
<div class="progress-bar bg-success" style="width: <%= allowed_percentage %>%">
|
|
<%= allowed_percentage %>% Allowed
|
|
</div>
|
|
<div class="progress-bar bg-danger" style="width: <%= blocked_percentage %>%">
|
|
<%= blocked_percentage %>% Blocked
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<div class="mt-4">
|
|
<%= link_to "View Events", events_project_path(@project), class: "btn btn-primary" %>
|
|
<%= link_to "Export Data", "#", class: "btn btn-secondary", onclick: "alert('Export feature coming soon!')" %>
|
|
</div> |