ATS/templates/recruitment/source_detail.html
2026-02-01 19:47:32 +03:00

624 lines
37 KiB
HTML

{% extends "base.html" %}
{% load static i18n %}
{% block title %}{{ source.name }} - {% trans "Source Details" %}{% endblock %}
{% block content %}
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<!-- Breadcrumb -->
<nav aria-label="breadcrumb" class="mb-6">
<ol class="flex items-center gap-2 text-sm">
<li>
<a href="{% url 'source_list' %}"
class="text-gray-500 hover:text-temple-red transition-colors flex items-center gap-1">
<i data-lucide="database" class="w-4 h-4"></i>
{% trans "Source Settings" %}
</a>
</li>
<li class="text-gray-400">/</li>
<li class="text-temple-red font-semibold">{% trans "Source Detail" %}</li>
</ol>
</nav>
<!-- Page Header -->
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
<div>
<h1 class="text-2xl sm:text-3xl font-bold text-gray-900 mb-2 flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="database" class="w-6 h-6 text-temple-red"></i>
</div>
{{ source.name }}
</h1>
<p class="text-gray-500 text-sm sm:text-base">
{% trans "View and manage integration source details" %}
</p>
</div>
<div class="flex gap-3">
<button id="toggle-source-status"
type="button"
class="inline-flex items-center gap-2 px-5 py-3 border-2 {% if source.is_active %}border-yellow-500 text-yellow-600 hover:bg-yellow-50{% else %}border-emerald-500 text-emerald-600 hover:bg-emerald-50{% endif %} rounded-xl font-semibold transition"
hx-post="{% url 'toggle_source_status' source.pk %}"
hx-target="#toggle-source-status"
hx-select="#toggle-source-status"
hx-select-oob="#source-status"
hx-swap="outerHTML"
hx-confirm="{% blocktrans %}Are you sure you want to {{ source.is_active|yesno:'deactivate,activate' }} this source?{% endblocktrans %}">
<i data-lucide="{% if source.is_active %}pause{% else %}play{% endif %}" class="w-5 h-5"></i>
{% if source.is_active %}{% trans "Deactivate" %}{% else %}{% trans "Activate" %}{% endif %}
</button>
<a href="{% url 'source_update' source.pk %}"
class="inline-flex items-center gap-2 px-5 py-3 border-2 border-gray-200 text-gray-700 rounded-xl font-semibold hover:border-gray-300 transition">
<i data-lucide="edit-3" class="w-5 h-5"></i>
{% trans "Edit" %}
</a>
<a href="{% url 'source_delete' source.pk %}"
class="inline-flex items-center gap-2 px-5 py-3 bg-red-500 text-white rounded-xl font-semibold shadow-lg hover:shadow-xl transition">
<i data-lucide="trash-2" class="w-5 h-5"></i>
{% trans "Delete" %}
</a>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Main Content Column -->
<div class="lg:col-span-2 space-y-6">
<!-- Source Information Card -->
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="info" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "Source Information" %}</h2>
<p class="text-sm text-gray-500">{% trans "Basic integration details" %}</p>
</div>
</div>
</div>
<div class="p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="tag" class="w-4 h-4 text-gray-400"></i>
{% trans "Name" %}
</label>
<div class="text-gray-900 font-medium">{{ source.name }}</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="server" class="w-4 h-4 text-gray-400"></i>
{% trans "Type" %}
</label>
<span class="inline-block text-[10px] font-bold uppercase tracking-wide px-2.5 py-1 rounded-full bg-temple-red/10 text-temple-red border border-temple-red">
{{ source.get_source_type_display }}
</span>
</div>
</div>
{% if source.description %}
<div class="mt-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="align-left" class="w-4 h-4 text-gray-400"></i>
{% trans "Description" %}
</label>
<div class="text-gray-700 bg-gray-50 rounded-xl p-4">{{ source.description|linebreaks }}</div>
</div>
{% endif %}
<div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="mail" class="w-4 h-4 text-gray-400"></i>
{% trans "Contact Email" %}
</label>
<div>
{% if source.contact_email %}
<a href="mailto:{{ source.contact_email }}" class="text-temple-red hover:text-[#7a1a29] transition-colors">{{ source.contact_email }}</a>
{% else %}
<span class="text-gray-400">{% trans "Not specified" %}</span>
{% endif %}
</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="phone" class="w-4 h-4 text-gray-400"></i>
{% trans "Contact Phone" %}
</label>
<div>
{% if source.contact_phone %}
<span class="text-gray-700">{{ source.contact_phone }}</span>
{% else %}
<span class="text-gray-400">{% trans "Not specified" %}</span>
{% endif %}
</div>
</div>
</div>
<div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="power" class="w-4 h-4 text-gray-400"></i>
{% trans "Status" %}
</label>
<div id="source-status">
{% if source.is_active %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-emerald-100 text-emerald-700 font-semibold text-sm">
<i data-lucide="check-circle-2" class="w-4 h-4"></i> {% trans "Active" %}
</span>
{% else %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 font-semibold text-sm">
<i data-lucide="x-circle" class="w-4 h-4"></i> {% trans "Inactive" %}
</span>
{% endif %}
</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="shield" class="w-4 h-4 text-gray-400"></i>
{% trans "Requires Authentication" %}
</label>
<div>
{% if source.requires_auth %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-yellow-100 text-yellow-700 font-semibold text-sm">
<i data-lucide="lock" class="w-4 h-4"></i> {% trans "Yes" %}
</span>
{% else %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 font-semibold text-sm">
<i data-lucide="unlock" class="w-4 h-4"></i> {% trans "No" %}
</span>
{% endif %}
</div>
</div>
</div>
{% if source.webhook_url %}
<div class="mt-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="link" class="w-4 h-4 text-gray-400"></i>
{% trans "Webhook URL" %}
</label>
<div class="bg-gray-50 rounded-xl p-4">
<code class="text-sm text-temple-red break-all">{{ source.webhook_url }}</code>
</div>
</div>
{% endif %}
{% if source.api_timeout %}
<div class="mt-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="clock" class="w-4 h-4 text-gray-400"></i>
{% trans "API Timeout" %}
</label>
<div class="text-gray-700">{{ source.api_timeout }} {% trans "seconds" %}</div>
</div>
{% endif %}
{% if source.notes %}
<div class="mt-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="file-text" class="w-4 h-4 text-gray-400"></i>
{% trans "Notes" %}
</label>
<div class="text-gray-700 bg-gray-50 rounded-xl p-4">{{ source.notes|linebreaks }}</div>
</div>
{% endif %}
<div class="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6 pt-6 border-t border-gray-100">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="calendar-plus" class="w-4 h-4 text-gray-400"></i>
{% trans "Created" %}
</label>
<div class="text-gray-700">{{ source.created_at|date:"M d, Y H:i" }}</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="refresh-cw" class="w-4 h-4 text-gray-400"></i>
{% trans "Last Updated" %}
</label>
<div class="text-gray-700">{{ source.updated_at|date:"M d, Y H:i" }}</div>
</div>
</div>
</div>
</div>
<!-- Integration Logs Card -->
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white flex justify-between items-center">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="list" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "Recent Integration Logs" %}</h2>
<p class="text-sm text-gray-500">{% trans "Last 10 logs" %}</p>
</div>
</div>
</div>
<div class="p-6">
{% if integration_logs %}
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-4 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Timestamp" %}</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Method" %}</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Status" %}</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Response Time" %}</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-bold text-gray-700 tracking-wider whitespace-nowrap">{% trans "Details" %}</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-100">
{% for log in integration_logs %}
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-4 py-4 text-sm text-gray-700">
<small>{{ log.created_at|date:"M d, Y H:i:s" }}</small>
</td>
<td class="px-4 py-4">
<span class="inline-block text-[10px] font-bold uppercase tracking-wide px-2 py-0.5 rounded bg-gray-100 text-gray-600">
{{ log.method }}
</span>
</td>
<td class="px-4 py-4">
{% if log.status_code >= 200 and log.status_code < 300 %}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-emerald-100 text-emerald-700 font-semibold text-xs">
<i data-lucide="check-circle" class="w-3 h-3"></i> {{ log.status_code }}
</span>
{% elif log.status_code >= 400 %}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-red-100 text-red-700 font-semibold text-xs">
<i data-lucide="x-circle" class="w-3 h-3"></i> {{ log.status_code }}
</span>
{% else %}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-yellow-100 text-yellow-700 font-semibold text-xs">
<i data-lucide="alert-circle" class="w-3 h-3"></i> {{ log.status_code }}
</span>
{% endif %}
</td>
<td class="px-4 py-4 text-sm text-gray-700">
{% if log.response_time_ms %}
<small>{{ log.response_time_ms }}ms</small>
{% else %}
<span class="text-gray-400">-</span>
{% endif %}
</td>
<td class="px-4 py-4">
{% if log.request_data %}
<button type="button"
class="inline-flex items-center justify-center w-8 h-8 rounded-lg border border-temple-red/30 text-temple-red hover:bg-temple-red hover:text-white transition"
onclick="openLogDetailModal({{ log.id }})"
title="{% trans 'View details' %}">
<i data-lucide="eye" class="w-4 h-4"></i>
</button>
{% else %}
<span class="text-gray-400 text-sm">{% trans "No data" %}</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-12">
<i data-lucide="clipboard-list" class="w-16 h-16 text-gray-300 mx-auto mb-4"></i>
<h3 class="text-lg font-semibold text-gray-900 mb-2">{% trans "No integration logs found" %}</h3>
<p class="text-gray-500">{% trans "There are no logs recorded for this source yet." %}</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Sidebar Column -->
<div class="space-y-6">
<!-- API Credentials Card -->
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="key" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "API Credentials" %}</h2>
<p class="text-sm text-gray-500">{% trans "API access keys" %}</p>
</div>
</div>
</div>
<div id="api-credentials" class="p-6 space-y-4">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="key" class="w-4 h-4 text-gray-400"></i>
{% trans "API Key" %}
</label>
<div class="flex">
<input type="text" value="{{ source.api_key }}" readonly
class="flex-1 px-4 py-2.5 border border-gray-200 border-r-0 rounded-l-xl bg-gray-50 text-sm focus:outline-none">
<button type="button"
hx-post="{% url 'copy_to_clipboard' %}"
hx-vals='{"text": "{{ source.api_key }}"}'
title="{% trans 'Copy to clipboard' %}"
class="inline-flex items-center justify-center px-3 border border-gray-200 bg-gray-100 hover:bg-gray-200 text-gray-600 rounded-r-xl transition">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="lock" class="w-4 h-4 text-gray-400"></i>
{% trans "API Secret" %}
</label>
<div class="flex">
<input type="password" value="{{ source.api_secret }}" readonly id="api-secret"
class="flex-1 px-4 py-2.5 border border-gray-200 rounded-l-xl bg-gray-50 text-sm focus:outline-none">
<button type="button" onclick="toggleSecretVisibility()"
class="inline-flex items-center justify-center px-3 border border-l-0 border-r-0 border-gray-200 bg-gray-100 hover:bg-gray-200 text-gray-600 transition">
<i data-lucide="eye" id="secret-toggle-icon" class="w-4 h-4"></i>
</button>
<button type="button"
hx-post="{% url 'copy_to_clipboard' %}"
hx-vals='{"text": "{{ source.api_secret }}"}'
title="{% trans 'Copy to clipboard' %}"
class="inline-flex items-center justify-center px-3 border border-l-0 border-gray-200 bg-gray-100 hover:bg-gray-200 text-gray-600 rounded-r-xl transition">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<div class="pt-2">
<a hx-post="{% url 'generate_api_keys' source.pk %}"
hx-target="#api-credentials"
hx-select="#api-credentials"
hx-swap="outerHTML"
class="inline-flex items-center justify-center gap-2 w-full px-5 py-3 bg-yellow-500 text-white rounded-xl font-semibold shadow hover:shadow-lg transition">
<i data-lucide="refresh-cw" class="w-5 h-5"></i>
{% trans "Generate New Keys" %}
</a>
</div>
</div>
</div>
<!-- Statistics Card -->
<div class="bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden">
<div class="px-6 py-4 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="bar-chart-2" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">{% trans "Integration Statistics" %}</h2>
<p class="text-sm text-gray-500">{% trans "API call metrics" %}</p>
</div>
</div>
</div>
<div class="p-6 space-y-4">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2">{% trans "Total API Calls" %}</label>
<div class="text-2xl font-bold text-gray-900">{{ total_logs }}</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2">{% trans "Successful Calls" %}</label>
<div class="text-2xl font-bold text-emerald-600">{{ successful_logs }}</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2">{% trans "Failed Calls" %}</label>
<div class="text-2xl font-bold text-red-600">{{ failed_logs }}</div>
</div>
{% if total_logs > 0 %}
<div class="pt-4 border-t border-gray-100">
<label class="text-sm font-semibold text-gray-700 mb-2">{% trans "Success Rate" %}</label>
<div class="text-2xl font-bold text-gray-900">
{% widthratio successful_logs total_logs 100 %}%
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Log Detail Modal -->
{% for log in integration_logs %}
{% if log.request_data %}
<div id="logDetailModal{{ log.id }}" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 hidden">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-3xl max-h-[90vh] overflow-hidden">
<div class="px-6 py-4 border-b border-gray-100 flex justify-between items-center bg-gradient-to-r from-gray-50 to-white">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-xl bg-temple-red/10 flex items-center justify-center">
<i data-lucide="file-text" class="w-5 h-5 text-temple-red"></i>
</div>
<div>
<h3 class="text-lg font-bold text-gray-900">{% trans "Integration Log Details" %}</h3>
<p class="text-sm text-gray-500">ID: {{ log.id }}</p>
</div>
</div>
<button type="button" onclick="closeLogDetailModal({{ log.id }})"
class="inline-flex items-center justify-center w-10 h-10 rounded-lg text-gray-400 hover:bg-gray-100 transition">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="p-6 overflow-y-auto max-h-[calc(90vh-80px)]">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="calendar" class="w-4 h-4 text-gray-400"></i>
{% trans "Timestamp" %}
</label>
<div class="text-gray-700 bg-gray-50 rounded-xl p-3">{{ log.created_at|date:"M d, Y H:i:s" }}</div>
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="git-commit" class="w-4 h-4 text-gray-400"></i>
{% trans "Method" %}
</label>
<span class="inline-block text-[10px] font-bold uppercase tracking-wide px-2 py-0.5 rounded bg-gray-100 text-gray-600">
{{ log.method }}
</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="badge-check" class="w-4 h-4 text-gray-400"></i>
{% trans "Status Code" %}
</label>
{% if log.status_code >= 200 and log.status_code < 300 %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-emerald-100 text-emerald-700 font-semibold text-sm">
<i data-lucide="check-circle-2" class="w-4 h-4"></i> {{ log.status_code }}
</span>
{% elif log.status_code >= 400 %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-red-100 text-red-700 font-semibold text-sm">
<i data-lucide="x-circle" class="w-4 h-4"></i> {{ log.status_code }}
</span>
{% else %}
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-yellow-100 text-yellow-700 font-semibold text-sm">
<i data-lucide="alert-circle" class="w-4 h-4"></i> {{ log.status_code }}
</span>
{% endif %}
</div>
<div>
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="zap" class="w-4 h-4 text-gray-400"></i>
{% trans "Response Time" %}
</label>
<div class="text-gray-700 bg-gray-50 rounded-xl p-3">
{% if log.response_time_ms %}
{{ log.response_time_ms }}ms
{% else %}
-
{% endif %}
</div>
</div>
</div>
<div class="mb-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="upload" class="w-4 h-4 text-gray-400"></i>
{% trans "Request Data" %}
</label>
<pre class="bg-gray-900 text-gray-100 rounded-xl p-4 overflow-x-auto text-sm"><code>{{ log.request_data|pprint }}</code></pre>
</div>
{% if log.response_data %}
<div class="mb-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="download" class="w-4 h-4 text-gray-400"></i>
{% trans "Response Data" %}
</label>
<pre class="bg-gray-900 text-gray-100 rounded-xl p-4 overflow-x-auto text-sm"><code>{{ log.response_data|pprint }}</code></pre>
</div>
{% endif %}
{% if log.error_message %}
<div class="mb-6">
<label class="text-sm font-semibold text-gray-700 mb-2 flex items-center gap-2">
<i data-lucide="alert-triangle" class="w-4 h-4 text-gray-400"></i>
{% trans "Error Message" %}
</label>
<div class="bg-red-50 border border-red-200 rounded-xl p-4 text-red-700">{{ log.error_message }}</div>
</div>
{% endif %}
</div>
<div class="px-6 py-4 border-t border-gray-100 bg-gray-50 flex justify-end">
<button type="button" onclick="closeLogDetailModal({{ log.id }})"
class="inline-flex items-center gap-2 px-5 py-3 border-2 border-gray-200 text-gray-700 rounded-xl font-semibold hover:border-gray-300 transition">
<i data-lucide="x" class="w-5 h-5"></i>
{% trans "Close" %}
</button>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
{% endblock %}
{% block customJS %}
<script>
// Initialize Lucide icons
lucide.createIcons();
// Toggle Secret Visibility
function toggleSecretVisibility() {
const secretInput = document.getElementById('api-secret');
const toggleIcon = document.getElementById('secret-toggle-icon');
if (secretInput.type === 'password') {
secretInput.type = 'text';
toggleIcon.setAttribute('data-lucide', 'eye-off');
} else {
secretInput.type = 'password';
toggleIcon.setAttribute('data-lucide', 'eye');
}
lucide.createIcons();
}
// Open Log Detail Modal
function openLogDetailModal(logId) {
const modal = document.getElementById('logDetailModal' + logId);
if (modal) {
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
}
}
// Close Log Detail Modal
function closeLogDetailModal(logId) {
const modal = document.getElementById('logDetailModal' + logId);
if (modal) {
modal.classList.add('hidden');
document.body.style.overflow = '';
}
}
// Close modal on escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
document.querySelectorAll('[id^="logDetailModal"]').forEach(modal => {
if (!modal.classList.contains('hidden')) {
modal.classList.add('hidden');
document.body.style.overflow = '';
}
});
}
});
// Close modal when clicking outside
document.querySelectorAll('[id^="logDetailModal"]').forEach(modal => {
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.classList.add('hidden');
document.body.style.overflow = '';
}
});
});
// Handle HTMX copy to clipboard feedback
document.body.addEventListener('htmx:afterRequest', function(evt) {
if (evt.detail.successful && evt.detail.target.matches('[hx-post*="copy_to_clipboard"]')) {
const button = evt.detail.target;
const originalHTML = button.innerHTML;
button.innerHTML = '<i data-lucide="check" class="w-4 h-4"></i>';
button.classList.remove('bg-gray-100', 'hover:bg-gray-200', 'text-gray-600', 'border-gray-200');
button.classList.add('bg-emerald-500', 'text-white', 'border-emerald-500');
lucide.createIcons();
setTimeout(() => {
button.innerHTML = originalHTML;
button.classList.remove('bg-emerald-500', 'text-white', 'border-emerald-500');
button.classList.add('bg-gray-100', 'hover:bg-gray-200', 'text-gray-600', 'border-gray-200');
lucide.createIcons();
}, 2000);
}
});
// Auto-refresh after status toggle
document.body.addEventListener('htmx:afterRequest', function(evt) {
if (evt.detail.successful && evt.detail.target.matches('[hx-post*="toggle_source_status"]')) {
setTimeout(() => {
window.location.reload();
}, 500);
}
});
</script>
{% endblock %}