118 lines
3.7 KiB
Plaintext
118 lines
3.7 KiB
Plaintext
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1><%= @project.name %></h1>
|
|
<div>
|
|
<%= link_to "Edit", edit_project_path(@project), class: "btn btn-secondary" %>
|
|
<%= link_to "Events", project_events_path(@project), class: "btn btn-primary" %>
|
|
<%= link_to "Analytics", analytics_project_path(@project), class: "btn btn-info" %>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Project Status</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p><strong>Status:</strong>
|
|
<span class="badge bg-<%= @waf_status == 'active' ? 'success' : @waf_status == 'idle' ? 'warning' : 'danger' %>">
|
|
<%= @waf_status %>
|
|
</span>
|
|
</p>
|
|
<p><strong>Enabled:</strong>
|
|
<span class="badge bg-<%= @project.enabled? ? 'success' : 'secondary' %>">
|
|
<%= @project.enabled? ? 'Yes' : 'No' %>
|
|
</span>
|
|
</p>
|
|
<p><strong>Events (24h):</strong> <%= @event_count %></p>
|
|
<p><strong>Blocked (24h):</strong> <%= @blocked_count %></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>DSN Configuration</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p><strong>DSN:</strong></p>
|
|
<code><%= @project.dsn %></code>
|
|
<button class="btn btn-sm btn-outline-primary ms-2" onclick="copyDSN()">Copy</button>
|
|
|
|
<% if @project.internal_dsn.present? %>
|
|
<hr>
|
|
<p><strong>Internal DSN:</strong></p>
|
|
<code><%= @project.internal_dsn %></code>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Recent Events</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<% if @recent_events.any? %>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Time</th>
|
|
<th>IP</th>
|
|
<th>Action</th>
|
|
<th>Path</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% @recent_events.limit(5).each do |event| %>
|
|
<tr>
|
|
<td><%= event.timestamp.strftime("%H:%M:%S") %></td>
|
|
<td><%= event.ip_address %></td>
|
|
<td>
|
|
<span class="badge bg-<%= event.blocked? ? 'danger' : event.allowed? ? 'success' : 'warning' %>">
|
|
<%= event.waf_action %>
|
|
</span>
|
|
</td>
|
|
<td><code><%= event.request_path %></code></td>
|
|
<td><%= event.response_status %></td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="text-end">
|
|
<%= link_to "View All Events", project_events_path(@project), class: "btn btn-primary btn-sm" %>
|
|
</div>
|
|
<% else %>
|
|
<p class="text-muted">No events received yet.</p>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function copyDSN() {
|
|
const dsnElement = document.querySelector('code');
|
|
const textArea = document.createElement('textarea');
|
|
textArea.value = dsnElement.textContent;
|
|
document.body.appendChild(textArea);
|
|
textArea.select();
|
|
document.execCommand('copy');
|
|
document.body.removeChild(textArea);
|
|
|
|
// Show feedback
|
|
const button = event.target;
|
|
const originalText = button.textContent;
|
|
button.textContent = 'Copied!';
|
|
button.classList.add('btn-success');
|
|
setTimeout(() => {
|
|
button.textContent = originalText;
|
|
button.classList.remove('btn-success');
|
|
}, 2000);
|
|
}
|
|
</script> |