Files
redux-scraper/app/views/telegram_bot_logs/index.html.erb
2025-08-05 05:05:21 +00:00

216 lines
12 KiB
Plaintext

<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<h1 class="text-2xl font-semibold text-slate-900">Telegram Bot Audit Logs</h1>
<p class="mt-2 text-sm text-slate-700">
Comprehensive audit trail of all Telegram bot interactions and performance metrics.
</p>
</div>
<div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<div class="text-sm text-slate-600">
Showing <%= @telegram_bot_logs.count %> of <%= @telegram_bot_logs.total_count %> logs
</div>
</div>
</div>
<!-- Filter Form -->
<div class="mt-6 bg-white shadow sm:rounded-lg">
<div class="px-4 py-4 border-b border-slate-200">
<h3 class="text-lg font-medium text-slate-900">Filters</h3>
<%= form_with url: telegram_bot_logs_path, method: :get, local: true, class: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4" do |f| %>
<!-- User ID Filter -->
<div>
<%= f.label :telegram_user_id, "Telegram User ID", class: "block text-sm font-medium text-slate-700" %>
<%= f.number_field :telegram_user_id,
value: @filter_params[:telegram_user_id],
class: "mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm",
placeholder: "Enter user ID" %>
</div>
<!-- Status Filter -->
<div>
<%= f.label :status, "Status", class: "block text-sm font-medium text-slate-700" %>
<%= f.select :status,
options_for_select([["All Statuses", ""]] + @status_options.map { |s| [s.humanize, s] }, @filter_params[:status]),
{},
{ class: "mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" } %>
</div>
<!-- Date Range Filters -->
<div>
<%= f.label :start_date, "Start Date", class: "block text-sm font-medium text-slate-700" %>
<%= f.date_field :start_date,
value: @filter_params[:start_date],
class: "mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" %>
</div>
<div>
<%= f.label :end_date, "End Date", class: "block text-sm font-medium text-slate-700" %>
<%= f.date_field :end_date,
value: @filter_params[:end_date],
class: "mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" %>
</div>
<!-- Results Count Filters -->
<div>
<%= f.label :min_results, "Min Results", class: "block text-sm font-medium text-slate-700" %>
<%= f.number_field :min_results,
value: @filter_params[:min_results],
min: 0,
class: "mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm",
placeholder: "Min results" %>
</div>
<div>
<%= f.label :max_results, "Max Results", class: "block text-sm font-medium text-slate-700" %>
<%= f.number_field :max_results,
value: @filter_params[:max_results],
min: 0,
class: "mt-1 block w-full rounded-md border-slate-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm",
placeholder: "Max results" %>
</div>
<!-- Performance Filter -->
<div class="flex items-center">
<%= f.check_box :slow_requests,
{ checked: @filter_params[:slow_requests] == "true", class: "h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500" },
"true", "" %>
<%= f.label :slow_requests, "Show slow requests only", class: "ml-2 block text-sm text-slate-700" %>
</div>
<!-- Action Buttons -->
<div class="flex items-end gap-2">
<%= f.submit "Apply Filters", class: "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded text-sm" %>
<%= link_to "Clear", telegram_bot_logs_path, class: "bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded text-sm" %>
</div>
<% end %>
</div>
</div>
<!-- Logs Table -->
<% if @telegram_bot_logs.any? %>
<div class="mt-6 overflow-hidden bg-white shadow sm:rounded-lg">
<div class="p-3 sm:p-4">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-slate-300">
<thead>
<tr>
<th class="pb-2 text-left text-sm font-semibold text-slate-900">User</th>
<th class="pb-2 text-left text-sm font-semibold text-slate-900">Status</th>
<th class="pb-2 text-left text-sm font-semibold text-slate-900">Results</th>
<th class="pb-2 text-left text-sm font-semibold text-slate-900">Performance</th>
<th class="pb-2 text-left text-sm font-semibold text-slate-900">Timestamp</th>
<th class="relative pb-2"><span class="sr-only">Actions</span></th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200">
<% @telegram_bot_logs.each do |log| %>
<tr class="hover:bg-slate-50">
<td class="py-3 pr-4 text-sm">
<div class="font-medium text-slate-900 truncate max-w-32">
<%= log.user_display_name %>
</div>
<div class="text-slate-500 text-xs">
ID: <%= log.telegram_user_id %>
</div>
</td>
<td class="py-3 pr-4 text-sm">
<% status_color = case log.status
when "success"
"bg-green-100 text-green-800"
when "error"
"bg-red-100 text-red-800"
when "no_results"
"bg-yellow-100 text-yellow-800"
when "invalid_image"
"bg-orange-100 text-orange-800"
else
"bg-slate-100 text-slate-800"
end %>
<span class="<%= status_color %> inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium">
<%= log.status.humanize %>
</span>
</td>
<td class="py-3 pr-4 text-sm text-slate-500">
<div class="font-medium text-slate-900">
<%= log.search_results_count %>
</div>
<% if log.search_results_count > 0 %>
<div class="text-xs text-green-600">
matches found
</div>
<% else %>
<div class="text-xs text-slate-400">
no matches
</div>
<% end %>
</td>
<td class="py-3 pr-4 text-sm text-slate-500">
<% if log.has_performance_metrics? %>
<div class="text-xs space-y-1">
<div class="flex justify-between">
<span class="text-blue-600">Download:</span>
<span class="font-mono"><%= sprintf("%.3f", log.download_time) %>s</span>
</div>
<% if log.image_processing_time.present? %>
<div class="flex justify-between">
<span class="text-purple-600">Process:</span>
<span class="font-mono"><%= sprintf("%.3f", log.image_processing_time) %>s</span>
</div>
<% end %>
<div class="flex justify-between">
<span class="text-yellow-600">Fingerprint:</span>
<span class="font-mono"><%= sprintf("%.3f", log.fingerprint_computation_time) %>s</span>
</div>
<div class="flex justify-between">
<span class="text-green-600">Search:</span>
<span class="font-mono"><%= sprintf("%.3f", log.search_computation_time) %>s</span>
</div>
<div class="flex justify-between font-medium border-t pt-1">
<span>Total:</span>
<span class="font-mono
<%= log.total_request_time && log.total_request_time > 1.0 ? 'text-red-600' : 'text-slate-700' %>">
<%= log.total_request_time ? sprintf("%.3f", log.total_request_time) : 'N/A' %>s
</span>
</div>
</div>
<% else %>
<span class="text-slate-400 text-xs">No metrics</span>
<% end %>
</td>
<td class="py-3 pr-4 text-sm text-slate-500">
<div class="text-xs">
<%= log.request_timestamp.strftime("%m/%d/%Y") %>
</div>
<div class="text-xs font-mono">
<%= log.request_timestamp.strftime("%H:%M:%S") %>
</div>
<div class="text-xs text-slate-400">
<%= time_ago_in_words(log.request_timestamp) %> ago
</div>
</td>
<td class="py-3 text-right text-sm font-medium">
<%= link_to "View", telegram_bot_log_path(log),
class: "text-blue-600 hover:text-blue-800 font-medium" %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<!-- Pagination -->
<% if @telegram_bot_logs.respond_to?(:current_page) %>
<%= render "shared/pagination_controls", collection: @telegram_bot_logs %>
<% end %>
<% else %>
<div class="mt-6 bg-white shadow sm:rounded-lg">
<div class="px-4 py-6 text-center">
<div class="mx-auto h-12 w-12 text-slate-400">
<svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-12 h-12">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3-3v-6a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6a2.25 2.25 0 002.25 2.25h10.5A2.25 2.25 0 0019.5 15z" />
</svg>
</div>
<h3 class="mt-2 text-sm font-semibold text-slate-900">No logs found</h3>
<p class="mt-1 text-sm text-slate-500">No Telegram bot logs match your current filters.</p>
<div class="mt-6">
<%= link_to "Clear filters", telegram_bot_logs_path,
class: "inline-flex items-center rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600" %>
</div>
</div>
</div>
<% end %>
</div>