| {% extends "base.html" %} |
|
|
| {% block title %}{{ script.name }} - PyRunner{% endblock %} |
|
|
| {% block content %} |
| <div class="flex"> |
| {% include "cpanel/_sidebar.html" %} |
|
|
| <div class="flex-1 p-8"> |
| |
| <div class="mb-8"> |
| <nav class="flex items-center space-x-2 text-sm text-code-muted mb-4"> |
| <a href="{% url 'cpanel:script_list' %}" class="hover:text-code-accent">Scripts</a> |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/> |
| </svg> |
| <span class="text-code-text">{{ script.name }}</span> |
| </nav> |
|
|
| <div class="flex items-start justify-between"> |
| <div> |
| <h1 class="text-2xl font-bold text-code-text flex items-center"> |
| {{ script.name }} |
| {% if script.is_archived %} |
| <span class="ml-3 px-2 py-1 text-xs rounded bg-code-red/20 text-code-red">Archived</span> |
| {% elif script.is_enabled %} |
| <span class="ml-3 px-2 py-1 text-xs rounded bg-code-green/20 text-code-green">Enabled</span> |
| {% else %} |
| <span class="ml-3 px-2 py-1 text-xs rounded bg-code-yellow/20 text-code-yellow">Disabled</span> |
| {% endif %} |
| </h1> |
| {% if script.description %} |
| <p class="text-code-muted mt-1">{{ script.description }}</p> |
| {% endif %} |
| {% if script.tags.exists %} |
| <div class="flex flex-wrap gap-2 mt-3"> |
| {% for tag in script.tags.all %} |
| <a href="{% url 'cpanel:script_list' %}?tag={{ tag.pk }}" |
| class="inline-flex items-center px-2.5 py-1 text-xs rounded-full tag-{{ tag.color }} hover:opacity-80 transition-opacity"> |
| {{ tag.name }} |
| </a> |
| {% endfor %} |
| </div> |
| {% endif %} |
| </div> |
|
|
| |
| <div class="flex items-center space-x-3"> |
| {% if script.is_archived %} |
| |
| <form method="post" action="{% url 'cpanel:script_restore' pk=script.pk %}"> |
| {% csrf_token %} |
| <button type="submit" |
| class="px-4 py-2 bg-code-green hover:bg-code-green/90 text-white font-semibold rounded-lg transition-colors flex items-center space-x-2"> |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"/> |
| </svg> |
| <span>Restore</span> |
| </button> |
| </form> |
|
|
| <form method="post" action="{% url 'cpanel:script_delete' pk=script.pk %}" |
| onsubmit="return confirm('PERMANENTLY delete {{ script.name }}? This cannot be undone and will delete all run history.');"> |
| {% csrf_token %} |
| <button type="submit" |
| class="px-4 py-2 bg-code-red hover:bg-code-red/90 text-white font-semibold rounded-lg transition-colors flex items-center space-x-2"> |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/> |
| </svg> |
| <span>Delete</span> |
| </button> |
| </form> |
| {% else %} |
| |
| <form method="post" action="{% url 'cpanel:script_run' pk=script.pk %}"> |
| {% csrf_token %} |
| <button type="submit" |
| class="px-4 py-2 bg-code-green hover:bg-code-green/90 text-white font-semibold rounded-lg transition-colors flex items-center space-x-2 {% if not script.can_run %}opacity-50 cursor-not-allowed{% endif %}" |
| {% if not script.can_run %}disabled{% endif %}> |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/> |
| </svg> |
| <span>Run</span> |
| </button> |
| </form> |
|
|
| <a href="{% url 'cpanel:script_edit' pk=script.pk %}" |
| class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded-lg transition-colors flex items-center space-x-2"> |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/> |
| </svg> |
| <span>Edit</span> |
| </a> |
|
|
| <form method="post" action="{% url 'cpanel:script_toggle' pk=script.pk %}"> |
| {% csrf_token %} |
| <button type="submit" |
| class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-accent text-code-text rounded-lg transition-colors"> |
| {% if script.is_enabled %}Disable{% else %}Enable{% endif %} |
| </button> |
| </form> |
|
|
| <form method="post" action="{% url 'cpanel:script_archive' pk=script.pk %}" |
| onsubmit="return confirm('Archive {{ script.name }}? The script will be hidden and its schedule paused.');"> |
| {% csrf_token %} |
| <button type="submit" |
| class="px-4 py-2 bg-code-surface border border-code-border hover:border-code-red text-code-muted hover:text-code-red rounded-lg transition-colors flex items-center space-x-2"> |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/> |
| </svg> |
| <span>Archive</span> |
| </button> |
| </form> |
| {% endif %} |
| </div> |
| </div> |
| </div> |
|
|
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
| |
| <div class="lg:col-span-2 space-y-6"> |
| |
| <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden"> |
| <div class="px-4 py-3 border-b border-code-border bg-code-bg flex items-center justify-between"> |
| <span class="text-sm font-medium text-code-text">Python Code</span> |
| <span class="text-xs text-code-muted">{{ script.code|length }} chars</span> |
| </div> |
| <div id="code-viewer-container" style="height: 500px;" class="overflow-hidden"></div> |
| <textarea id="code-content" class="hidden">{{ script.code }}</textarea> |
| </div> |
| </div> |
|
|
| |
| <div class="space-y-6"> |
| |
| <div class="bg-code-surface border border-code-border rounded-xl p-6"> |
| <h3 class="text-sm font-semibold text-code-text mb-4">Script Info</h3> |
| <dl class="space-y-4"> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Environment</dt> |
| <dd class="text-code-text mt-1"> |
| <a href="{% url 'cpanel:environment_detail' pk=script.environment.pk %}" class="text-code-accent hover:underline"> |
| {{ script.environment.name }} |
| </a> |
| </dd> |
| </div> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Timeout</dt> |
| <dd class="text-code-text mt-1">{{ script.timeout_seconds }} seconds</dd> |
| </div> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Created</dt> |
| <dd class="text-code-text mt-1">{{ script.created_at|date:"M d, Y H:i" }}</dd> |
| </div> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Updated</dt> |
| <dd class="text-code-text mt-1">{{ script.updated_at|date:"M d, Y H:i" }}</dd> |
| </div> |
| {% if script.created_by %} |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Created By</dt> |
| <dd class="text-code-text mt-1">{{ script.created_by.email }}</dd> |
| </div> |
| {% endif %} |
| </dl> |
|
|
| {% if script.is_archived %} |
| <div class="mt-4 pt-4 border-t border-code-border"> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Archived</dt> |
| <dd class="text-code-red mt-1">{{ script.archived_at|date:"M d, Y H:i" }}</dd> |
| </div> |
| {% if script.archived_by %} |
| <div class="mt-2"> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Archived By</dt> |
| <dd class="text-code-text mt-1">{{ script.archived_by.email }}</dd> |
| </div> |
| {% endif %} |
| </div> |
| {% endif %} |
| </div> |
|
|
| |
| <div class="bg-code-surface border border-code-border rounded-xl p-6"> |
| <h3 class="text-sm font-semibold text-code-text mb-4">Statistics</h3> |
| <div class="grid grid-cols-2 gap-4"> |
| <div class="text-center p-3 bg-code-bg rounded-lg"> |
| <div class="text-2xl font-bold text-code-accent">{{ script.run_count }}</div> |
| <div class="text-xs text-code-muted">Total Runs</div> |
| </div> |
| <div class="text-center p-3 bg-code-bg rounded-lg"> |
| <div class="text-2xl font-bold {% if script.success_rate >= 80 %}text-code-green{% elif script.success_rate >= 50 %}text-code-yellow{% else %}text-code-red{% endif %}"> |
| {% if script.run_count > 0 %}{{ script.success_rate|floatformat:0 }}%{% else %}-{% endif %} |
| </div> |
| <div class="text-xs text-code-muted">Success Rate</div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mt-6"> |
| |
| <div class="bg-code-surface border border-code-border rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-sm font-semibold text-code-text">Schedule</h3> |
| {% if schedule.run_mode != 'manual' %} |
| <form method="post" action="{% url 'cpanel:schedule_toggle' pk=script.pk %}"> |
| {% csrf_token %} |
| <button type="submit" class="text-xs px-2 py-1 rounded {% if schedule.is_active %}bg-code-green/20 text-code-green{% else %}bg-code-yellow/20 text-code-yellow{% endif %}"> |
| {% if schedule.is_active %}Active{% else %}Paused{% endif %} |
| </button> |
| </form> |
| {% endif %} |
| </div> |
|
|
| <dl class="space-y-4"> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Mode</dt> |
| <dd class="text-code-text mt-1">{{ schedule.schedule_display }}</dd> |
| </div> |
|
|
| {% if schedule.next_run %} |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Next Run</dt> |
| <dd class="text-code-text mt-1">{{ schedule.next_run|date:"M d, Y H:i" }} UTC</dd> |
| </div> |
| {% endif %} |
|
|
| {% if schedule.last_scheduled_run %} |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Last Scheduled Run</dt> |
| <dd class="text-code-text mt-1">{{ schedule.last_scheduled_run|date:"M d, Y H:i" }} UTC</dd> |
| </div> |
| {% endif %} |
| </dl> |
|
|
| <div class="mt-4 pt-4 border-t border-code-border"> |
| <a href="{% url 'cpanel:schedule_history' pk=script.pk %}" class="text-xs text-code-accent hover:underline"> |
| View schedule history |
| </a> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-code-surface border border-code-border rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-sm font-semibold text-code-text">Webhook</h3> |
| {% if script.has_webhook %} |
| <span class="text-xs px-2 py-1 rounded bg-code-green/20 text-code-green">Enabled</span> |
| {% else %} |
| <span class="text-xs px-2 py-1 rounded bg-code-muted/20 text-code-muted">Disabled</span> |
| {% endif %} |
| </div> |
|
|
| {% if script.has_webhook %} |
| <div class="space-y-4"> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider mb-2">Webhook URL <span class="text-code-yellow">(sensitive)</span></dt> |
| <div class="flex items-center space-x-2"> |
| <input type="password" |
| id="webhook-url" |
| value="{{ request.scheme }}://{{ request.get_host }}{% url 'webhook_trigger' token=script.webhook_token %}" |
| readonly |
| class="flex-1 px-3 py-2 bg-code-bg border border-code-border rounded text-code-text text-xs font-mono"> |
| <button type="button" |
| onclick="toggleWebhookVisibility()" |
| id="webhook-toggle-btn" |
| class="px-3 py-2 bg-code-bg hover:bg-code-border text-code-muted text-xs rounded transition-colors border border-code-border" |
| title="Show/Hide URL"> |
| <svg id="webhook-eye-icon" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/> |
| </svg> |
| </button> |
| <button type="button" |
| onclick="copyWebhookUrl()" |
| class="px-3 py-2 bg-code-accent hover:bg-code-accent/90 text-white text-xs rounded transition-colors" |
| title="Copy URL"> |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/> |
| </svg> |
| </button> |
| </div> |
| </div> |
|
|
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider mb-2">Example curl</dt> |
| <button type="button" |
| id="curl-toggle-btn" |
| onclick="toggleCurlExample()" |
| class="text-xs text-code-accent hover:underline mb-2"> |
| Show example |
| </button> |
| <pre id="curl-example" class="hidden p-3 bg-code-bg rounded text-xs font-mono text-code-muted overflow-x-auto">curl -X POST \ |
| -H "Content-Type: application/json" \ |
| -d '{"key": "value"}' \ |
| "{{ request.scheme }}://{{ request.get_host }}{% url 'webhook_trigger' token=script.webhook_token %}"</pre> |
| </div> |
|
|
| <div class="flex items-center space-x-2 pt-2"> |
| <form method="post" action="{% url 'cpanel:webhook_regenerate' pk=script.pk %}" |
| onsubmit="return confirm('Regenerate webhook URL? The old URL will stop working.');"> |
| {% csrf_token %} |
| <button type="submit" class="text-xs text-code-yellow hover:underline"> |
| Regenerate URL |
| </button> |
| </form> |
| <span class="text-code-muted">|</span> |
| <form method="post" action="{% url 'cpanel:webhook_disable' pk=script.pk %}" |
| onsubmit="return confirm('Disable webhook? The URL will stop working.');"> |
| {% csrf_token %} |
| <button type="submit" class="text-xs text-code-red hover:underline"> |
| Disable |
| </button> |
| </form> |
| </div> |
| </div> |
| {% else %} |
| <p class="text-code-muted text-sm mb-4">Enable webhooks to trigger this script via HTTP requests from external services.</p> |
| <form method="post" action="{% url 'cpanel:webhook_enable' pk=script.pk %}"> |
| {% csrf_token %} |
| <button type="submit" class="px-4 py-2 bg-code-accent hover:bg-code-accent/90 text-white text-sm rounded transition-colors"> |
| Enable Webhook |
| </button> |
| </form> |
| {% endif %} |
| </div> |
|
|
| |
| <div class="bg-code-surface border border-code-border rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <h3 class="text-sm font-semibold text-code-text">Notifications</h3> |
| {% if script.notify_on != 'never' %} |
| <span class="text-xs px-2 py-1 rounded bg-code-accent/20 text-code-accent"> |
| {{ script.get_notify_on_display }} |
| </span> |
| {% else %} |
| <span class="text-xs px-2 py-1 rounded bg-code-muted/20 text-code-muted">Disabled</span> |
| {% endif %} |
| </div> |
|
|
| {% if script.notify_on != 'never' %} |
| <dl class="space-y-4"> |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Notify On</dt> |
| <dd class="text-code-text mt-1">{{ script.get_notify_on_display }}</dd> |
| </div> |
|
|
| {% if script.notify_email %} |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Email Override</dt> |
| <dd class="text-code-text mt-1">{{ script.notify_email }}</dd> |
| </div> |
| {% else %} |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Email</dt> |
| <dd class="text-code-muted mt-1 text-sm">Using global default</dd> |
| </div> |
| {% endif %} |
|
|
| {% if script.notify_webhook_enabled and script.notify_webhook_url %} |
| <div> |
| <dt class="text-xs text-code-muted uppercase tracking-wider">Webhook</dt> |
| <dd class="text-code-text mt-1 text-sm break-all">{{ script.notify_webhook_url }}</dd> |
| </div> |
| {% endif %} |
| </dl> |
| {% else %} |
| <p class="text-code-muted text-sm"> |
| Notifications are disabled for this script. |
| <a href="{% url 'cpanel:script_edit' pk=script.pk %}" class="text-code-accent hover:underline"> |
| Edit settings |
| </a> |
| </p> |
| {% endif %} |
| </div> |
| </div> |
|
|
| |
| <div class="mt-8"> |
| <h2 class="text-lg font-semibold text-code-text mb-4">Recent Runs</h2> |
|
|
| {% if recent_runs %} |
| <div class="bg-code-surface border border-code-border rounded-xl overflow-hidden"> |
| <table class="w-full"> |
| <thead class="bg-code-bg border-b border-code-border"> |
| <tr> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Status</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Duration</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Triggered By</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider">Started</th> |
| <th class="px-6 py-3 text-left text-xs font-semibold text-code-muted uppercase tracking-wider"></th> |
| </tr> |
| </thead> |
| <tbody class="divide-y divide-code-border"> |
| {% for run in recent_runs %} |
| <tr class="hover:bg-code-bg/50 transition-colors"> |
| <td class="px-6 py-4"> |
| {% if run.status == 'success' %} |
| <span class="px-2 py-1 text-xs rounded bg-code-green/20 text-code-green">Success</span> |
| {% elif run.status == 'failed' %} |
| <span class="px-2 py-1 text-xs rounded bg-code-red/20 text-code-red">Failed</span> |
| {% elif run.status == 'timeout' %} |
| <span class="px-2 py-1 text-xs rounded bg-code-red/20 text-code-red">Timeout</span> |
| {% elif run.status == 'running' %} |
| <span class="px-2 py-1 text-xs rounded bg-code-yellow/20 text-code-yellow">Running</span> |
| {% elif run.status == 'pending' %} |
| <span class="px-2 py-1 text-xs rounded bg-code-muted/20 text-code-muted">Pending</span> |
| {% elif run.status == 'cancelled' %} |
| <span class="px-2 py-1 text-xs rounded bg-code-muted/20 text-code-muted">Cancelled</span> |
| {% endif %} |
| </td> |
| <td class="px-6 py-4 text-code-text"> |
| {% if run.duration_display %}{{ run.duration_display }}{% else %}-{% endif %} |
| </td> |
| <td class="px-6 py-4 text-code-muted"> |
| {% if run.triggered_by %}{{ run.triggered_by.email }}{% else %}System{% endif %} |
| </td> |
| <td class="px-6 py-4 text-code-muted text-sm"> |
| {% if run.started_at %}{{ run.started_at|date:"M d, H:i" }}{% else %}{{ run.created_at|date:"M d, H:i" }}{% endif %} |
| </td> |
| <td class="px-6 py-4 text-right"> |
| <a href="{% url 'cpanel:run_detail' pk=run.pk %}" class="text-code-accent hover:underline text-sm"> |
| View |
| </a> |
| </td> |
| </tr> |
| {% endfor %} |
| </tbody> |
| </table> |
| </div> |
| {% else %} |
| <div class="bg-code-surface border border-code-border rounded-xl p-8 text-center"> |
| <p class="text-code-muted">No runs yet. Click "Run" to execute this script.</p> |
| </div> |
| {% endif %} |
| </div> |
| </div> |
| </div> |
|
|
| <script src="https://cdn.jsdelivr.net/npm/monaco-editor@0.45.0/min/vs/loader.js"></script> |
| <script> |
| require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.45.0/min/vs' } }); |
| require(['vs/editor/editor.main'], function () { |
| const container = document.getElementById('code-viewer-container'); |
| const codeContent = document.getElementById('code-content'); |
| |
| monaco.editor.create(container, { |
| value: codeContent.value, |
| language: 'python', |
| theme: 'vs-dark', |
| fontSize: 14, |
| fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace", |
| minimap: { enabled: false }, |
| scrollBeyondLastLine: false, |
| lineNumbers: 'on', |
| readOnly: true, |
| automaticLayout: true |
| }); |
| }); |
| </script> |
|
|
| <script> |
| function copyWebhookUrl() { |
| const urlInput = document.getElementById('webhook-url'); |
| if (urlInput) { |
| navigator.clipboard.writeText(urlInput.value).then(() => { |
| |
| const btn = event.currentTarget; |
| const originalHTML = btn.innerHTML; |
| btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>'; |
| setTimeout(() => { |
| btn.innerHTML = originalHTML; |
| }, 1500); |
| }).catch(err => { |
| |
| urlInput.select(); |
| document.execCommand('copy'); |
| }); |
| } |
| } |
| |
| function toggleWebhookVisibility() { |
| const urlInput = document.getElementById('webhook-url'); |
| const eyeIcon = document.getElementById('webhook-eye-icon'); |
| if (urlInput.type === 'password') { |
| urlInput.type = 'text'; |
| eyeIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/>'; |
| } else { |
| urlInput.type = 'password'; |
| eyeIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>'; |
| } |
| } |
| |
| function toggleCurlExample() { |
| const curlExample = document.getElementById('curl-example'); |
| const toggleBtn = document.getElementById('curl-toggle-btn'); |
| if (curlExample.classList.contains('hidden')) { |
| curlExample.classList.remove('hidden'); |
| toggleBtn.textContent = 'Hide example'; |
| } else { |
| curlExample.classList.add('hidden'); |
| toggleBtn.textContent = 'Show example'; |
| } |
| } |
| </script> |
| {% endblock %} |
|
|