Download templates/index.html from Opera8/runflare: direct link, hf CLI and curl.
- Browser
- Download file 17.6 kB
-
https://huggingface.co/spaces/Opera8/runflare/resolve/main/templates/index.html
- Command line
-
hf download hf://spaces/Opera8/runflare/templates/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Opera8/runflare/resolve/main/templates/index.html
17.6 kB
| <html lang="fa" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>داشبورد هوشمند مدیریت گیتهاب اکشنز</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;600;800&display=swap" rel="stylesheet"> | |
| <style> | |
| body { | |
| font-family: 'Vazirmatn', system-ui, -apple-system, sans-serif; | |
| background-color: #0f172a; | |
| color: #f1f5f9; | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen py-10 px-4"> | |
| <div class="max-w-6xl w-full mx-auto bg-slate-900 border border-slate-800 rounded-2xl shadow-2xl p-6 md:p-8"> | |
| <!-- Header --> | |
| <header class="text-center mb-8 border-b border-slate-800 pb-6 flex flex-col md:flex-row md:justify-between md:items-center"> | |
| <div class="text-right"> | |
| <h1 class="text-3xl font-extrabold text-blue-500 mb-2">داشبورد مدیریت گیتهاب اکشنز</h1> | |
| <p class="text-slate-400 text-sm">مانیتورینگ، پاکسازی و مدیریت فرآیندها به صورت آنی</p> | |
| </div> | |
| <div class="mt-4 md:mt-0 flex gap-3 flex-wrap"> | |
| <a href="/fluxpro" class="bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-4 rounded-lg text-sm transition-colors">ابزار Flux Pro</a> | |
| <a href="/flux2" class="bg-teal-600 hover:bg-teal-700 text-white font-semibold py-2 px-4 rounded-lg text-sm transition-colors">ابزار FLUX.2</a> | |
| </div> | |
| </header> | |
| <!-- Stats Grid --> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"> | |
| <div class="bg-slate-800/40 p-6 rounded-xl border border-slate-800 flex flex-col items-center shadow-lg"> | |
| <span class="text-xs font-semibold text-slate-400 mb-1">اکشنهای در حال کار</span> | |
| <span id="activeCount" class="text-3xl font-bold text-yellow-500">۰</span> | |
| </div> | |
| <div class="bg-slate-800/40 p-6 rounded-xl border border-slate-800 flex flex-col items-center shadow-lg"> | |
| <span class="text-xs font-semibold text-slate-400 mb-1">اکشنهای غیرفعال امروز</span> | |
| <span id="inactiveCount" class="text-3xl font-bold text-blue-500">۰</span> | |
| </div> | |
| <div class="bg-slate-800/40 p-6 rounded-xl border border-slate-800 flex flex-col items-center shadow-lg"> | |
| <span class="text-xs font-semibold text-slate-400 mb-1">کارهای موفق امروز</span> | |
| <span id="completedCount" class="text-3xl font-bold text-green-500">۰</span> | |
| </div> | |
| </div> | |
| <!-- Action Control Buttons --> | |
| <div class="bg-slate-800/20 border border-slate-800/80 p-6 rounded-xl mb-8"> | |
| <h3 class="text-lg font-bold text-slate-300 mb-4 text-right">عملیات کنترلی</h3> | |
| <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4"> | |
| <button onclick="loadActiveActions()" class="bg-yellow-600/20 border border-yellow-500/30 text-yellow-400 hover:bg-yellow-600/30 font-semibold py-2.5 px-4 rounded-lg text-sm transition-all"> | |
| دیدن اکشنهای در حال کار | |
| </button> | |
| <button onclick="loadInactiveToday()" class="bg-blue-600/20 border border-blue-500/30 text-blue-400 hover:bg-blue-600/30 font-semibold py-2.5 px-4 rounded-lg text-sm transition-all"> | |
| دیدن اکشنهای غیر فعال امروز | |
| </button> | |
| <button onclick="loadCompletedTodayCount()" class="bg-green-600/20 border border-green-500/30 text-green-400 hover:bg-green-600/30 font-semibold py-2.5 px-4 rounded-lg text-sm transition-all"> | |
| تعداد کارهای انجام شده امروز | |
| </button> | |
| <button onclick="deleteInactive()" class="bg-red-600/20 border border-red-500/30 text-red-400 hover:bg-red-600/30 font-semibold py-2.5 px-4 rounded-lg text-sm transition-all"> | |
| حذف تمام اکشنهای غیرفعال | |
| </button> | |
| <button onclick="deleteFailedCompleted()" class="bg-rose-600/20 border border-rose-500/30 text-rose-400 hover:bg-rose-600/30 font-semibold py-2.5 px-4 rounded-lg text-sm transition-all"> | |
| حذف تمام تکمیل شده و خطا زده | |
| </button> | |
| <button onclick="cancelDeleteActive()" class="bg-orange-600/20 border border-orange-500/30 text-orange-400 hover:bg-orange-600/30 font-semibold py-2.5 px-4 rounded-lg text-sm transition-all"> | |
| غیرفعال کردن اکشنهای فعال و حذف آنها | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Table for Displaying List --> | |
| <div id="displayContainer" class="hidden border border-slate-800 bg-slate-950/40 rounded-2xl p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 id="tableTitle" class="text-lg font-bold text-slate-300">لیست فرآیندها</h3> | |
| <span id="tableLoading" class="hidden text-sm text-blue-400 animate-pulse">در حال بروزرسانی...</span> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="w-full text-right text-sm text-slate-300"> | |
| <thead class="bg-slate-800 text-xs text-slate-400"> | |
| <tr> | |
| <th class="p-3 rounded-r-lg">شناسه اکشن</th> | |
| <th class="p-3">نام اکشن</th> | |
| <th class="p-3">وضعیت</th> | |
| <th class="p-3">نتیجه</th> | |
| <th class="p-3">زمان شروع</th> | |
| <th class="p-3 rounded-l-lg text-left">لینک گیتهاب</th> | |
| </tr> | |
| </thead> | |
| <tbody id="runsListTable"> | |
| <!-- Dynamic Rows --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Alert messages --> | |
| <div id="statusAlert" class="hidden mt-6 bg-slate-800 border border-slate-700 text-slate-300 text-sm rounded-xl p-4 text-right shadow-md"></div> | |
| </div> | |
| <script> | |
| window.addEventListener('load', () => { | |
| updateStats(); | |
| }); | |
| async function updateStats() { | |
| try { | |
| const resActive = await fetch('/api/actions/active'); | |
| const dataActive = await resActive.json(); | |
| if (dataActive.status === 'success') { | |
| document.getElementById('activeCount').textContent = dataActive.actions.length; | |
| } | |
| const resInactive = await fetch('/api/actions/inactive-today'); | |
| const dataInactive = await resInactive.json(); | |
| if (dataInactive.status === 'success') { | |
| document.getElementById('inactiveCount').textContent = dataInactive.actions.length; | |
| } | |
| const resCompleted = await fetch('/api/actions/completed-today-count'); | |
| const dataCompleted = await resCompleted.json(); | |
| if (dataCompleted.status === 'success') { | |
| document.getElementById('completedCount').textContent = dataCompleted.count; | |
| } | |
| } catch (e) { | |
| console.error('Error updating dashboard stats:', e); | |
| } | |
| } | |
| function showAlert(msg, isSuccess = true) { | |
| const alert = document.getElementById('statusAlert'); | |
| alert.textContent = msg; | |
| alert.className = isSuccess | |
| ? 'mt-6 bg-emerald-950/40 border border-emerald-900 text-emerald-300 text-sm rounded-xl p-4 text-right shadow-md' | |
| : 'mt-6 bg-rose-950/40 border border-rose-900 text-rose-300 text-sm rounded-xl p-4 text-right shadow-md'; | |
| alert.classList.remove('hidden'); | |
| setTimeout(() => { alert.classList.add('hidden'); }, 5000); | |
| } | |
| async function loadActiveActions() { | |
| const container = document.getElementById('displayContainer'); | |
| const tbody = document.getElementById('runsListTable'); | |
| const title = document.getElementById('tableTitle'); | |
| const loading = document.getElementById('tableLoading'); | |
| container.classList.remove('hidden'); | |
| loading.classList.remove('hidden'); | |
| tbody.innerHTML = ''; | |
| title.textContent = 'اکشنهای در حال کار (Queued / In Progress)'; | |
| try { | |
| const res = await fetch('/api/actions/active'); | |
| const data = await res.json(); | |
| loading.classList.add('hidden'); | |
| if (data.status === 'success' && data.actions.length > 0) { | |
| data.actions.forEach(action => { | |
| const row = ` | |
| <tr class="border-b border-slate-800/50 hover:bg-slate-800/30"> | |
| <td class="p-3 font-mono">${action.id}</td> | |
| <td class="p-3 font-semibold text-slate-200">${action.name}</td> | |
| <td class="p-3"><span class="px-2 py-1 text-xs font-semibold rounded bg-yellow-950/40 text-yellow-400 border border-yellow-900">${action.status}</span></td> | |
| <td class="p-3 text-slate-400">نامعلوم</td> | |
| <td class="p-3 text-xs text-slate-400">${new Date(action.created_at).toLocaleString('fa-IR')}</td> | |
| <td class="p-3 text-left"><a href="${action.html_url}" target="_blank" class="text-blue-400 hover:underline">دیدن در گیتهاب</a></td> | |
| </tr> | |
| `; | |
| tbody.insertAdjacentHTML('beforeend', row); | |
| }); | |
| } else { | |
| tbody.innerHTML = '<tr><td colspan="6" class="p-4 text-center text-slate-500">هیچ اکشن فعال در حال کارهای شما نیست.</td></tr>'; | |
| } | |
| } catch (e) { | |
| loading.classList.add('hidden'); | |
| showAlert('خطا در دریافت اطلاعات!', false); | |
| } | |
| } | |
| async function loadInactiveToday() { | |
| const container = document.getElementById('displayContainer'); | |
| const tbody = document.getElementById('runsListTable'); | |
| const title = document.getElementById('tableTitle'); | |
| const loading = document.getElementById('tableLoading'); | |
| container.classList.remove('hidden'); | |
| loading.classList.remove('hidden'); | |
| tbody.innerHTML = ''; | |
| title.textContent = 'اکشنهای غیر فعال امروز (Completed)'; | |
| try { | |
| const res = await fetch('/api/actions/inactive-today'); | |
| const data = await res.json(); | |
| loading.classList.add('hidden'); | |
| if (data.status === 'success' && data.actions.length > 0) { | |
| data.actions.forEach(action => { | |
| let badgeColor = action.conclusion === 'success' ? 'bg-emerald-950/40 text-emerald-400 border-emerald-900' : 'bg-rose-950/40 text-rose-400 border-rose-900'; | |
| const row = ` | |
| <tr class="border-b border-slate-800/50 hover:bg-slate-800/30"> | |
| <td class="p-3 font-mono">${action.id}</td> | |
| <td class="p-3 font-semibold text-slate-200">${action.name}</td> | |
| <td class="p-3"><span class="px-2 py-1 text-xs font-semibold rounded bg-blue-950/40 text-blue-400 border border-blue-900">${action.status}</span></td> | |
| <td class="p-3"><span class="px-2 py-1 text-xs font-semibold rounded border ${badgeColor}">${action.conclusion || 'نامعلوم'}</span></td> | |
| <td class="p-3 text-xs text-slate-400">${new Date(action.created_at).toLocaleString('fa-IR')}</td> | |
| <td class="p-3 text-left"><a href="${action.html_url}" target="_blank" class="text-blue-400 hover:underline">دیدن در گیتهاب</a></td> | |
| </tr> | |
| `; | |
| tbody.insertAdjacentHTML('beforeend', row); | |
| }); | |
| } else { | |
| tbody.innerHTML = '<tr><td colspan="6" class="p-4 text-center text-slate-500">هیچ اکشن غیرفعالشدهای برای امروز ثبت نشده است.</td></tr>'; | |
| } | |
| } catch (e) { | |
| loading.classList.add('hidden'); | |
| showAlert('خطا در دریافت اطلاعات!', false); | |
| } | |
| } | |
| async function loadCompletedTodayCount() { | |
| try { | |
| const res = await fetch('/api/actions/completed-today-count'); | |
| const data = await res.json(); | |
| if (data.status === 'success') { | |
| showAlert(`تعداد کارهای با موفقیت انجام شده امروز: ${data.count} عدد`, true); | |
| updateStats(); | |
| } | |
| } catch (e) { | |
| showAlert('خطا در دریافت اطلاعات آمار امروز!', false); | |
| } | |
| } | |
| async function deleteInactive() { | |
| if (!confirm('آیا مطمئن هستید که میخواهید تمام اکشنهای غیرفعال را حذف کنید؟ این عمل غیر قابل بازگشت است.')) return; | |
| showAlert('در حال ارسال درخواست پاکسازی اکشنهای غیرفعال از گیتهاب...', true); | |
| try { | |
| const res = await fetch('/api/actions/delete-inactive', { method: 'POST' }); | |
| const data = await res.json(); | |
| if (data.status === 'success') { | |
| showAlert(`عملیات موفقیتآمیز بود! تعداد ${data.deleted_count} اکشن غیرفعال با موفقیت حذف شد.`, true); | |
| updateStats(); | |
| document.getElementById('displayContainer').classList.add('hidden'); | |
| } else { | |
| showAlert('خطایی در انجام فرآیند حذف رخ داد.', false); | |
| } | |
| } catch (e) { | |
| showAlert('خطای ارتباط با سرور بکاند!', false); | |
| } | |
| } | |
| async function deleteFailedCompleted() { | |
| if (!confirm('آیا مطمئن هستید که میخواهید تمام اکشنهای تکمیلشده، خطا زده و کنسل شده را به صورت کامل حذف کنید؟')) return; | |
| showAlert('در حال ارسال درخواست پاکسازی اکشنهای تکمیل شده و خطا زده از گیتهاب...', true); | |
| try { | |
| const res = await fetch('/api/actions/delete-failed-completed', { method: 'POST' }); | |
| const data = await res.json(); | |
| if (data.status === 'success') { | |
| showAlert(`عملیات موفقیتآمیز بود! تعداد ${data.deleted_count} اکشن تکمیل شده یا خطا زده با موفقیت حذف گردید.`, true); | |
| updateStats(); | |
| document.getElementById('displayContainer').classList.add('hidden'); | |
| } else { | |
| showAlert('خطایی در انجام فرآیند حذف رخ داد.', false); | |
| } | |
| } catch (e) { | |
| showAlert('خطای ارتباط با سرور بکاند!', false); | |
| } | |
| } | |
| async function cancelDeleteActive() { | |
| if (!confirm('آیا مطمئن هستید که میخواهید تمام اکشنهای فعال در حال اجرا را لغو (متوقف) و به طور کامل حذف کنید؟')) return; | |
| showAlert('در حال ارسال درخواست لغو و حذف اکشنهای فعال به گیتهاب...', true); | |
| try { | |
| const res = await fetch('/api/actions/cancel-delete-active', { method: 'POST' }); | |
| const data = await res.json(); | |
| if (data.status === 'success') { | |
| showAlert(`عملیات با موفقیت انجام شد! تعداد ${data.cancelled_count} اکشن فعال لغو شد و ${data.deleted_count} اکشن متوقف شده با موفقیت حذف گردید.`, true); | |
| updateStats(); | |
| document.getElementById('displayContainer').classList.add('hidden'); | |
| } else { | |
| showAlert('خطایی در انجام فرآیند لغو و حذف رخ داد.', false); | |
| } | |
| } catch (e) { | |
| showAlert('خطای ارتباط با سرور بکاند!', false); | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> |