178 lines
8.6 KiB
Text
178 lines
8.6 KiB
Text
<Layouts.app flash={@flash}>
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<!-- Header -->
|
|
<div class="mb-6">
|
|
<nav class="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 mb-4">
|
|
<.link navigate={~p"/devices"} class="hover:text-gray-700 dark:hover:text-gray-300">
|
|
{t("Devices")}
|
|
</.link>
|
|
<span>/</span>
|
|
<.link
|
|
navigate={~p"/devices/#{@device.id}"}
|
|
class="hover:text-gray-700 dark:hover:text-gray-300"
|
|
>
|
|
{@device.name}
|
|
</.link>
|
|
<span>/</span>
|
|
<.link
|
|
navigate={~p"/devices/#{@device.id}?tab=backups"}
|
|
class="hover:text-gray-700 dark:hover:text-gray-300"
|
|
>
|
|
{t("Backups")}
|
|
</.link>
|
|
<span>/</span>
|
|
<span class="text-gray-900 dark:text-white">Compare</span>
|
|
</nav>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
|
|
{t("Compare Configuration Backups")}
|
|
</h1>
|
|
<.link
|
|
navigate={~p"/devices/#{@device.id}?tab=backups"}
|
|
class="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-700"
|
|
>
|
|
<.icon name="hero-arrow-left" class="h-4 w-4" /> Back to Backups
|
|
</.link>
|
|
</div>
|
|
</div>
|
|
<!-- Backup Info Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
|
<!-- Backup A -->
|
|
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-4">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">Backup A (Older)</h3>
|
|
<button
|
|
phx-click="download_config"
|
|
phx-value-backup="a"
|
|
class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
|
|
>
|
|
<.icon name="hero-arrow-down-tray" class="h-4 w-4" /> Download
|
|
</button>
|
|
</div>
|
|
<dl class="space-y-1 text-sm">
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-500 dark:text-gray-400">Date:</dt>
|
|
<dd class="text-gray-900 dark:text-white font-mono">
|
|
{ToweropsWeb.TimeHelpers.format_iso8601(
|
|
@backup_a.backed_up_at,
|
|
@current_scope.timezone,
|
|
@current_scope.time_format
|
|
)}
|
|
</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-500 dark:text-gray-400">Size:</dt>
|
|
<dd class="text-gray-900 dark:text-white font-mono">
|
|
{format_bytes(@backup_a.config_size_bytes)}
|
|
</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-500 dark:text-gray-400">Source:</dt>
|
|
<dd>
|
|
<span class={[
|
|
"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium",
|
|
@backup_a.trigger_source == "daily_cron" &&
|
|
"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
|
|
@backup_a.trigger_source == "manual" &&
|
|
"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
|
|
]}>
|
|
{String.replace(@backup_a.trigger_source, "_", " ") |> String.capitalize()}
|
|
</span>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
<!-- Backup B -->
|
|
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-4">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">Backup B (Newer)</h3>
|
|
<button
|
|
phx-click="download_config"
|
|
phx-value-backup="b"
|
|
class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
|
|
>
|
|
<.icon name="hero-arrow-down-tray" class="h-4 w-4" /> Download
|
|
</button>
|
|
</div>
|
|
<dl class="space-y-1 text-sm">
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-500 dark:text-gray-400">Date:</dt>
|
|
<dd class="text-gray-900 dark:text-white font-mono">
|
|
{ToweropsWeb.TimeHelpers.format_iso8601(
|
|
@backup_b.backed_up_at,
|
|
@current_scope.timezone,
|
|
@current_scope.time_format
|
|
)}
|
|
</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-500 dark:text-gray-400">Size:</dt>
|
|
<dd class="text-gray-900 dark:text-white font-mono">
|
|
{format_bytes(@backup_b.config_size_bytes)}
|
|
</dd>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<dt class="text-gray-500 dark:text-gray-400">Source:</dt>
|
|
<dd>
|
|
<span class={[
|
|
"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium",
|
|
@backup_b.trigger_source == "daily_cron" &&
|
|
"bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
|
|
@backup_b.trigger_source == "manual" &&
|
|
"bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
|
|
]}>
|
|
{String.replace(@backup_b.trigger_source, "_", " ") |> String.capitalize()}
|
|
</span>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
<!-- Diff Stats -->
|
|
<%= if @diff_output == "" do %>
|
|
<div class="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-4 mb-6">
|
|
<div class="flex items-center gap-2">
|
|
<.icon name="hero-check-circle" class="h-5 w-5 text-green-600 dark:text-green-400" />
|
|
<p class="text-sm text-green-800 dark:text-green-200">
|
|
{t("These backups are identical. No differences found.")}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<% else %>
|
|
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 p-4 mb-6">
|
|
<div class="flex items-center gap-6 text-sm">
|
|
<div class="flex items-center gap-2">
|
|
<span class="inline-block w-3 h-3 bg-green-500 rounded-sm"></span>
|
|
<span class="text-gray-600 dark:text-gray-400">
|
|
{@stats.additions} addition{if @stats.additions != 1, do: "s"}
|
|
</span>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<span class="inline-block w-3 h-3 bg-red-500 rounded-sm"></span>
|
|
<span class="text-gray-600 dark:text-gray-400">
|
|
{@stats.deletions} deletion{if @stats.deletions != 1, do: "s"}
|
|
</span>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<span class="inline-block w-3 h-3 bg-yellow-500 rounded-sm"></span>
|
|
<span class="text-gray-600 dark:text-gray-400">
|
|
{@stats.changes} change{if @stats.changes != 1, do: "s"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Unified Diff Display -->
|
|
<div class="bg-white dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-white/10 overflow-hidden">
|
|
<div class="px-4 py-3 border-b border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-gray-800/75">
|
|
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">
|
|
{t("Configuration Differences")}
|
|
</h3>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<pre class="p-4 text-xs font-mono leading-relaxed"><code><%= for line <- String.split(@diff_output, "\n") do %><%= cond do %><% String.starts_with?(line, "+") && !String.starts_with?(line, "+++") -> %><span class="block bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200">{line}</span><% String.starts_with?(line, "-") && !String.starts_with?(line, "---") -> %><span class="block bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200">{line}</span><% String.starts_with?(line, "@@") -> %><span class="block bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 font-semibold">{line}</span><% String.starts_with?(line, "---") || String.starts_with?(line, "+++") -> %><span class="block text-gray-500 dark:text-gray-500 italic">{line}</span><% true -> %><span class="block text-gray-700 dark:text-gray-300">{line}</span><% end %><% end %></code></pre>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</Layouts.app>
|