{% extends ../base.html %} {% block meta %} {% end %} {% block title %}Crafty Controller - {{ translate('serverDetails', 'serverDetails', data['lang']) }}{% end %} {% block content %} <div class="content-wrapper"> <!-- Page Title Header Starts--> <div class="row page-title-header"> <div class="col-12"> <div class="page-header"> <h4 class="page-title"> {{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{ data['server_stats']['server_id']['server_name'] }} <br /> <small>UUID: {{ data['server_stats']['server_id']['server_id'] }}</small> </h4> </div> </div> </div> <!-- Page Title Header Ends--> {% include "parts/details_stats.html" %} <div class="row"> <div class="col-sm-12 grid-margin"> <div class="card"> <div class="card-body pt-0"> <span class="d-none d-sm-block"> {% include "parts/server_controls_list.html" %} </span> <span class="d-block d-sm-none"> {% include "parts/m_server_controls_list.html" %} </span> <div class="row"> <div class="col-md-12 col-sm-12" style="overflow-x:auto;"> <div class="card"> <div class="card-header header-sm d-flex justify-content-between align-items-center"> <h4 class="card-title"><i class="fa-regular fa-bell"></i> {{ translate('webhooks', 'webhooks', data['lang']) }} </h4> {% if data['user_data']['hints'] %} <span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" , data-placement="bottom"></span> {% end %} <div><a class="btn btn-info" href="/panel/add_webhook?id={{ data['server_stats']['server_id']['server_id'] }}"><i class="fas fa-plus-circle"></i> {{ translate('webhooks', 'new', data['lang']) }}</a></div> </div> <div class="card-body"> {% if len(data['webhooks']) == 0 %} <div style="text-align: center; color: grey;"> <h7>{{ translate('webhooks', 'no-webhook', data['lang']) }} <strong>{{ translate('webhooks', 'newWebhook',data['lang']) }}</strong>.</h7> </div> {% end %} {% if len(data['webhooks']) > 0 %} <div class="d-none d-lg-block"> <table class="table table-hover responsive-table" aria-label="webhooks list" id="webhook_table" width="100%" style="table-layout:fixed;"> <thead> <tr class="rounded"> <th scope="col" style="width: 5%; min-width: 64px;">{{ translate('webhooks', 'enabled', data['lang']) }}</th> <th scope="col" style="width: 15%; min-width: 10px;">{{ translate('webhooks', 'name', data['lang']) }} </th> <th scope="col" style="width: 20%; min-width: 50px;">{{ translate('webhooks', 'type', data['lang']) }}</th> <th scope="col" style="width: 50%; min-width: 50px;">{{ translate('webhooks', 'trigger', data['lang']) }}</th> <th scope="col" style="width: 10%; min-width: 50px;">{{ translate('webhooks', 'edit', data['lang']) }}</th> </tr> </thead> <tbody> {% for webhook in data['webhooks'] %} <tr> <td id="{{webhook.enabled}}" class="enabled"> <button type="button" class="btn btn-sm btn-info btn-toggle webhook-custom-toggle" id="webhook_{{webhook.id}}" name="webhook_{{webhook.id}}" data-webhook-id="{{webhook.id}}" data-webhook-enabled="{{ 'true' if webhook.enabled else 'false' }}" data-toggle="button" aria-pressed="true" autocomplete="off"> <div class="handle"></div> </button> </td> <td id="{{webhook.name}}" class="id"> <p>{{webhook.name}}</p> </td> <td id="{{webhook.webhook_type}}" class="type"> <p>{{webhook.webhook_type}}</p> </td> <td id="{{webhook.trigger}}" class="trigger" style="overflow: scroll; max-width: 30px;"> <ul> {% for trigger in webhook.trigger.split(",") %} {% if trigger in data["triggers"] %} <li>{{translate('webhooks', trigger , data['lang'])}}</li> {%end%} {%end%} </ul> </td> <td id="webhook_edit" class="action"> <button onclick="window.location.href=`/panel/webhook_edit?id={{ data['server_stats']['server_id']['server_id'] }}&webhook_id={{webhook.id}}`" class="btn btn-info"> <i class="fas fa-pencil-alt"></i> </button> <button data-webhook={{ webhook.id }} class="btn btn-danger del_button"> <i class="fas fa-trash" aria-hidden="true"></i> </button> <button data-webhook={{ webhook.id }} data-toggle="tooltip" title="{{ translate('webhooks', 'run', data['lang']) }}" class="btn btn-outline-warning test-socket"> <i class="fa-solid fa-vial"></i> </button> </td> </tr> {% end %} </tbody> </table> </div> <div class="d-block d-lg-none"> <table aria-label="webhooks list" class="table table-hover responsive-table" id="webhook_table_mini" width="100%" style="table-layout:fixed;"> <thead> <tr class="rounded"> <th style="width: 20%; min-width: 64px;">{{ translate('webhooks', 'enabled', data['lang']) }}</th> <th style="width: 40%; min-width: 10px;">Name </th> <th style="width: 40%; min-width: 50px;">{{ translate('webhooks', 'edit', data['lang']) }}</th> </tr> </thead> <tbody> {% for webhook in data['webhooks'] %} <tr> <td id="{{webhook.enabled}}" class="enabled"> <button type="button" class="btn btn-sm btn-info btn-toggle webhook-custom-toggle" id="webhook_{{webhook.id}}" name="webhook_{{webhook.id}}" data-webhook-id="{{webhook.id}}" data-webhook-enabled="{{ 'true' if webhook.enabled else 'false' }}" data-toggle="button" aria-pressed="true" autocomplete="off"> <div class="handle"></div> </button> </td> <td id="{{webhook.name}}" class="id"> <p>{{webhook.name}}</p> </td> <td id="webhook_edit" class="action"> <button onclick="window.location.href=`/panel/webhook_edit?id={{ data['server_stats']['server_id']['server_id'] }}&webhook_id={{webhook.id}}`" class="btn btn-info"> <i class="fas fa-pencil-alt"></i> </button> <button data-webhook={{ webhook.id }} class="btn btn-danger del_button"> <i class="fas fa-trash" aria-hidden="true"></i> </button> <button data-webhook={{ webhook.id }} data-toggle="tooltip" title="{{ translate('webhooks', 'run', data['lang']) }}" class="btn btn-outline-warning test-socket"> <i class="fa-solid fa-vial"></i> </button> </td> </tr> {% end %} </tbody> </table> </div> {% end %} </div> </div> </div> </div> </div> </div> </div> </div> <style> .popover-body { color: white !important; ; } .toggle-handle { background-color: white !important; } .toggle-on { color: black !important; } .toggle { height: 0px !important; } td.enabled { vertical-align: middle; border-collapse: collapse !important; } .enabled .toggle-group .btn { vertical-align: middle; cursor: pointer; } </style> </div> <style> /* Hide scrollbar for Chrome, Safari and Opera */ td::-webkit-scrollbar { display: none; } /* Hide scrollbar for IE, Edge and Firefox */ td { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } </style> <!-- content-wrapper ends --> {% end %} {% block js %} <script> $(document).ready(function () { console.log('ready for JS!') $('#webhook_table').DataTable({ 'order': [4, 'asc'], } ); $('#webhook_table_mini').DataTable({ 'order': [2, 'asc'] } ); document.getElementById('webhook_table_mini_wrapper').hidden = true; }); $(document).ready(function () { $('[data-toggle="popover"]').popover(); if ($(window).width() < 1000) { $('.too_small').popover("show"); document.getElementById('webhook_table_wrapper').hidden = true; document.getElementById('webhook_table_mini_wrapper').hidden = false; } }); $(window).ready(function () { $('body').click(function () { $('.too_small').popover("hide"); }); }); $(window).resize(function () { // This will execute whenever the window is resized if ($(window).width() < 1000) { $('.too_small').popover("show"); document.getElementById('webhook_table_wrapper').hidden = true; document.getElementById('webhook_table_mini_wrapper').hidden = false; } else { $('.too_small').popover("hide"); document.getElementById('webhook_table_wrapper').hidden = false; document.getElementById('webhook_table_mini_wrapper').hidden = true; } // New width }); function debounce(func, timeout = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; } $(document).ready(function () { $('.webhook-custom-toggle').each(function () { const enabled = JSON.parse(this.getAttribute('data-webhook-enabled')); if (enabled) { this.classList.add("active"); } else { this.classList.remove("active"); } }) }); $(() => { $('.webhook-custom-toggle').click(function () { const id = this.getAttribute('data-webhook-id'); const enabled = !JSON.parse(this.getAttribute('data-webhook-enabled')); fetch(`/api/v2/servers/{{data['server_id']}}/webhook/${id}`, { method: 'PATCH', body: JSON.stringify({ enabled }), headers: { 'Content-Type': 'application/json', }, }) }); }) const serverId = new URLSearchParams(document.location.search).get('id') </script> <script> //used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } $(document).ready(function () { console.log("ready!"); }); $(".del_button").click(function () { var webhook_id = $(this).data('webhook'); bootbox.confirm({ message: "{{ translate('webhooks', 'areYouSureDel', data['lang']) }}", buttons: { cancel: { label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data["lang"]) }}' }, confirm: { className: 'btn-outline-danger', label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data["lang"]) }}' } }, callback: function (result) { console.log(result); if (result == true) { del_hook(webhook_id, serverId); } } }); }); $(".test-socket").click(function () { var webhook_id = $(this).data('webhook'); bootbox.confirm({ message: "{{ translate('webhooks', 'areYouSureRun', data['lang']) }}", buttons: { cancel: { label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data["lang"]) }}' }, confirm: { className: 'btn-outline-danger', label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data["lang"]) }}' } }, callback: function (result) { console.log(result); if (result == true) { test_hook(webhook_id, serverId); } } }); }); async function test_hook(webhook_id, id) { var token = getCookie("_xsrf") let res = await fetch(`/api/v2/servers/${id}/webhook/${webhook_id}/`, { method: 'POST', headers: { 'token': token, }, }); let responseData = await res.json(); if (responseData.status === "ok") { bootbox.alert("Webhook Sent!") } else { console.log(responseData); bootbox.alert({ title: responseData.status, message: responseData.error }); } } async function del_hook(webhook_id, id) { var token = getCookie("_xsrf") let res = await fetch(`/api/v2/servers/${id}/webhook/${webhook_id}`, { method: 'DELETE', headers: { 'token': token, }, }); let responseData = await res.json(); if (responseData.status === "ok") { window.location.reload(); } else { bootbox.alert({ title: responseData.status, message: responseData.error }); } } </script> {% end %}