mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
586 lines
26 KiB
HTML
586 lines
26 KiB
HTML
{% extends 'base.html' %}
|
|
|
|
{% block content %}
|
|
|
|
<form method="post" id="general_form" action="">
|
|
|
|
<!-- Page header -->
|
|
<div class="page-header mt-0 d-print-none">
|
|
<div class="container-xl">
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col">
|
|
<!-- Page pre-title -->
|
|
<div class="page-pretitle">
|
|
Settings
|
|
</div>
|
|
<h2 class="page-title">
|
|
General
|
|
</h2>
|
|
</div>
|
|
<!-- Page title actions -->
|
|
<div class="col-auto ms-auto d-print-none">
|
|
<div class="btn-list">
|
|
<button type="submit" class="btn btn-primary">Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="toastContainer" class="position-static"></div>
|
|
|
|
|
|
<!-- Page body -->
|
|
<div class="page-body">
|
|
<div class="container-xl">
|
|
<div class="row row-deck row-cards">
|
|
|
|
<div class="col-lg-12">
|
|
<span id="public_ip_for_js" style="display:none;">{{ public_ip }}</span>
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Global Settings</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Both panels are accessible on:</label>
|
|
<div class="row form-selectgroup form-selectgroup-boxes d-flex">
|
|
<div class="col-lg-6">
|
|
<label class="form-selectgroup-item flex-fill">
|
|
<input type="radio" name="form-domain-name-is-set" id="customDomain" value="domain_name" class="form-selectgroup-input" {% if config_data['DEFAULT']['force_domain'] %}checked=""{% endif %}>
|
|
<div class="form-selectgroup-label d-flex align-items-center p-3">
|
|
<div class="me-3">
|
|
<span class="form-selectgroup-check"></span>
|
|
</div>
|
|
<div>
|
|
<div class="font-weight-medium">Custom Domain Name <span
|
|
class="form-help"
|
|
data-bs-toggle="popover"
|
|
data-bs-placement="top"
|
|
data-bs-content="<p class='mb-0'>Make sure that the domain is set as server hostname and is a <a target='_blank' id='linkWikipediaFQDN' href='https://en.wikipedia.org/wiki/FQDN'>FQDN</a>.</p>"
|
|
data-bs-html="true"
|
|
>?</span></div>
|
|
<input type="text" class="form-control" name="force_domain" placeholder="{{ server_hostname }}" value="{% if 'force_domain' in config_data['DEFAULT'] and config_data['DEFAULT']['force_domain'] %}{{ config_data['DEFAULT']['force_domain'] }}{% else %}{{ server_hostname }}{% endif %}">
|
|
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<label class="form-selectgroup-item flex-fill">
|
|
<input type="radio" name="form-domain-name-not-set-use-shared-ip" value="ip_address" class="form-selectgroup-input" id="serverIPAddress" {% if not config_data['DEFAULT']['force_domain'] %}checked=""{% endif %}>
|
|
<div class="form-selectgroup-label d-flex align-items-center p-3">
|
|
<div class="me-3">
|
|
<span class="form-selectgroup-check"></span>
|
|
</div>
|
|
<div>
|
|
<div class="font-weight-medium">Server IP address</div>
|
|
|
|
<input type="text" class="form-control" name="force_domain_is_empty" placeholder="Input placeholder" value="{{public_ip}}" disabled="">
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">AdminPanel Settings</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">AdminPanel port:</label>
|
|
<div class="input-group input-group-flat">
|
|
<span class="input-group-text" id="2087_prepend">
|
|
{% if force_domain %}
|
|
https://{{ config_data['DEFAULT']['force_domain'] }}:
|
|
{% else %}
|
|
http://{{ public_ip }}:
|
|
{% endif %}
|
|
</span>
|
|
<input type="number" class="form-control ps-0" name="2087_port" value="2087" autocomplete="off" min="1000" max="33000" disabled>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Force SSL:</label>
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="ssl_checkbox" {%if config_data['DEFAULT']['ssl'] == 'yes' %}checked=""{% endif %} name="ssl">
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">OpenPanel Settings</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">OpenPanel port:</label>
|
|
<div class="input-group input-group-flat">
|
|
<span class="input-group-text" id="2083_prepend">
|
|
{% if force_domain %}
|
|
https://{{ config_data['DEFAULT']['force_domain'] }}:
|
|
{% else %}
|
|
http://{{ public_ip }}:
|
|
{% endif %}
|
|
</span>
|
|
<input type="number" class="form-control ps-0" name="2083_port" autocomplete="off" value="{{ config_data['DEFAULT']['port'] }}" min="1000" max="33000">
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">OpenPanel is also available on:</label>
|
|
<div class="input-group input-group-flat">
|
|
<span class="input-group-text" id="2083_prepend">https://customer-domain.com/</span>
|
|
<input type="text" class="form-control ps-0" name="openpanel_proxy" autocomplete="off" placeholder="openpanel" value="{% if 'openpanel_proxy' in config_data['DEFAULT'] and config_data['DEFAULT']['openpanel_proxy'] %}{{ config_data['DEFAULT']['openpanel_proxy'] }}{% endif %}">
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="col-lg-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Update preferences</h4>
|
|
<div id="update_is_available" style="display:none;" class="ribbon bg-primary">Update is available!</div>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<div class="mb-3">
|
|
<div class="row d-flex">
|
|
|
|
<div class="col-lg-6">
|
|
<p>Local OpenPanel version: <b id="local_version">{{panel_version}}</b></p>
|
|
|
|
<p>Latest OpenPanel version: <b id="latest_version">{{panel_version}}</b><a href="https://openpanel.com/docs/changelog/{{panel_version}}" target="_blank" style="display:none;" id="view_changelog">View Changelog</a></p>
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
|
|
<a href="#" data-bs-toggle="modal" id="update_now_button" data-bs-target="#update_now_modal" style="display:none;" class="btn"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-refresh"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" /><path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" /></svg> Update now
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="mb-3">
|
|
<div class="row form-selectgroup form-selectgroup-boxes d-flex">
|
|
|
|
<div class="col-lg-6">
|
|
<label class="form-selectgroup-item flex-fill">
|
|
<input type="checkbox" name="autoupdate" value="on" class="form-selectgroup-input" {%if config_data['PANEL']['autoupdate'] == 'on' %}checked=""{% endif %}>
|
|
<div class="form-selectgroup-label d-flex align-items-center p-3">
|
|
<div class="me-3">
|
|
<span class="form-selectgroup-check"></span>
|
|
</div>
|
|
<div class="form-selectgroup-label-content d-flex align-items-center">
|
|
|
|
<div>
|
|
<div class="font-weight-medium">Auto Updates</div>
|
|
<div class="text-secondary">Automatically update to all <b>major</b> versions of OpenPanel <a href="https://openpanel.com/docs/admin/intro/#enable-automatic-updates" target="_blank">( <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 15l6 -6" /><path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" /><path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" /></svg> Docs)</a></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<label class="form-selectgroup-item flex-fill">
|
|
<input type="checkbox" name="autopatch" value="on" class="form-selectgroup-input" {%if config_data['PANEL']['autopatch'] == 'on'%}checked=""{% endif %}>
|
|
<div class="form-selectgroup-label d-flex align-items-center p-3">
|
|
<div class="me-3">
|
|
<span class="form-selectgroup-check"></span>
|
|
</div>
|
|
<div class="form-selectgroup-label-content d-flex align-items-center">
|
|
|
|
<div>
|
|
<div class="font-weight-medium">Auto Patches</div>
|
|
<div class="text-secondary">Automatically update to all <b>minor</b> versions of OpenPanel <a href="https://openpanel.com/docs/admin/intro/#disable-automatic-updates" target="_blank">( <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 15l6 -6" /><path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" /><path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" /></svg> Docs)</a></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- run update process now - confirm modal -->
|
|
<div class="modal modal-blur fade" id="update_now_modal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
|
<div class="modal-content">
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
<div class="modal-status bg-success"></div>
|
|
<div class="modal-body text-center py-4">
|
|
<!-- Modal content goes here -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon mb-2 text-green icon-lg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M9 12l2 2l4 -4" /></svg>
|
|
<h3>Confirm update to OpenPanel <span id="version_in_modal"></span></h3>
|
|
<div class="text-secondary">The update process for OpenPanel will last approximately 5 minutes. During this period, access to both OpenPanel and OpenAdmin interfaces will be temporarily unavailable. However, user websites will remain operational without any interruption.</div>
|
|
|
|
<div class="mt-2 text-secondary">Please confirm to start the update now.
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<div class="w-100">
|
|
<div class="row">
|
|
<div class="col"><a href="#" class="btn w-100" data-bs-dismiss="modal">
|
|
Cancel update
|
|
</a></div>
|
|
<div class="col"><button id="start_update_btn" class="btn btn-success w-100">
|
|
Start update process
|
|
</button></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!--script src="{{ url_for('static', filename='pages/general_settings.js') }}" defer></script-->
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
// Get the radio buttons and port input fields
|
|
var domainRadio = document.querySelector('input[name="form-domain-name-is-set"]');
|
|
var ipRadio = document.querySelector('input[name="form-domain-name-not-set-use-shared-ip"]');
|
|
var adminPortInput = document.querySelector('input[name="2087_port"]');
|
|
var adminPortPrepend = document.getElementById('2087_prepend');
|
|
var openPortInput = document.querySelector('input[name="2083_port"]');
|
|
var openPortPrepend = document.getElementById('2083_prepend');
|
|
var sslCheckbox = document.getElementById('ssl_checkbox');
|
|
|
|
|
|
// Add event listener for Force SSL checkbox
|
|
sslCheckbox.addEventListener("change", function () {
|
|
// Update the protocol in the prepend text based on the checkbox state
|
|
updatePrependText();
|
|
});
|
|
|
|
// Add event listeners for radio buttons
|
|
domainRadio.addEventListener("change", function() {
|
|
if (domainRadio.checked) {
|
|
// Update the prepend text for AdminPanel and OpenPanel ports
|
|
updatePrependText();
|
|
}
|
|
});
|
|
|
|
ipRadio.addEventListener("change", function() {
|
|
if (ipRadio.checked) {
|
|
// Update the prepend text for AdminPanel and OpenPanel ports
|
|
var protocol = sslCheckbox.checked ? "https://" : "http://";
|
|
adminPortPrepend.textContent = protocol + "{{ public_ip }}:";
|
|
openPortPrepend.textContent = protocol + "{{ public_ip }}:";
|
|
}
|
|
});
|
|
|
|
// Add event listener for custom domain input
|
|
var domainInput = document.querySelector('input[name="force_domain"]');
|
|
domainInput.addEventListener("input", function() {
|
|
// If the user starts typing, check domainRadio and uncheck ipRadio
|
|
if (!domainRadio.checked) {
|
|
domainRadio.checked = true;
|
|
ipRadio.checked = false;
|
|
// Update the prepend text for AdminPanel and OpenPanel ports
|
|
updatePrependText();
|
|
}
|
|
|
|
// If domainInput is empty, switch to ipRadio
|
|
if (domainInput.value.trim() === "") {
|
|
domainRadio.checked = false;
|
|
ipRadio.checked = true;
|
|
// Update the prepend text for AdminPanel and OpenPanel ports
|
|
updatePrependText();
|
|
} else {
|
|
// Update the prepend text for AdminPanel and OpenPanel ports based on the custom domain input
|
|
updatePrependText();
|
|
}
|
|
});
|
|
|
|
|
|
|
|
|
|
// Function to update prepend text for AdminPanel and OpenPanel ports
|
|
function updatePrependText() {
|
|
var protocol = sslCheckbox.checked ? "https://" : "http://";
|
|
// Retrieve the public IP address text from the element
|
|
var publicIp = document.getElementById('public_ip_for_js').textContent;
|
|
|
|
if (ipRadio.checked) {
|
|
adminPortPrepend.textContent = protocol + publicIp + ":";
|
|
openPortPrepend.textContent = protocol + publicIp + ":";
|
|
}
|
|
if (domainRadio.checked) {
|
|
var customDomain = domainInput.value.trim();
|
|
adminPortPrepend.textContent = protocol + customDomain + ":";
|
|
openPortPrepend.textContent = protocol + customDomain + ":";
|
|
}
|
|
}
|
|
|
|
// UPDATE BUTTON
|
|
$('#start_update_btn').click(function(e) {
|
|
e.preventDefault();
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: '/settings/general/update_now',
|
|
success: function(response) {
|
|
$('#update_now_modal .modal-body').html('<div class="text-center py-4">' + response.message + '</div>');
|
|
$('#update_now_modal .modal-footer').html('');
|
|
},
|
|
error: function(error) {
|
|
$('#update_now_modal .modal-body').html('<div class="text-danger">Failed to start the update process. Please try again later.</div>');
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const customDomainCheckbox = document.getElementById('customDomain');
|
|
const serverIPAddressCheckbox = document.getElementById('serverIPAddress');
|
|
|
|
customDomainCheckbox.addEventListener('change', function () {
|
|
serverIPAddressCheckbox.checked = false;
|
|
});
|
|
|
|
serverIPAddressCheckbox.addEventListener('change', function () {
|
|
customDomainCheckbox.checked = false;
|
|
});
|
|
});
|
|
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
var form = document.getElementById('general_form');
|
|
var toastContainer = document.createElement('div');
|
|
toastContainer.classList.add('toast-container', 'position-fixed', 'bottom-0', 'end-0', 'p-3');
|
|
document.body.appendChild(toastContainer);
|
|
|
|
form.addEventListener('submit', function (event) {
|
|
event.preventDefault(); // Prevent the default form submission
|
|
|
|
// Perform AJAX submission
|
|
var formData = new FormData(form);
|
|
|
|
fetch(form.action, {
|
|
method: form.method,
|
|
body: formData,
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
// Check for success messages
|
|
if (data.success_messages && data.success_messages.length > 0) {
|
|
// Display success toasts
|
|
displayToasts(data.success_messages, 'success');
|
|
|
|
// Check for the specific success message
|
|
if (data.success_messages.some(msg => msg.includes("Panels are accessible on IP address"))) {
|
|
// Display a new toast for redirection message
|
|
var portValue = document.querySelector('input[name="2087_port"]').value;
|
|
var public_ip = "{{ public_ip }}";
|
|
|
|
// Construct the redirect URL
|
|
var redirectURL = `http://${public_ip}:${portValue}/settings/general`;
|
|
|
|
displayToasts([`Redirecting to: ${redirectURL}`], 'info');
|
|
|
|
// Redirect after 5 seconds
|
|
setTimeout(function() {
|
|
// Redirect the user
|
|
window.location.href = redirectURL;
|
|
}, 5000);
|
|
} else if (data.success_messages.some(msg => msg.includes("is set as the domain name for both panels"))) {
|
|
// Redirect for the new success message condition
|
|
var portValue = document.querySelector('input[name="2087_port"]').value;
|
|
var server_hostname = "{{ server_hostname }}";
|
|
|
|
// Construct the redirect URL
|
|
var redirectURL = `https://${server_hostname}:${portValue}/settings/general`;
|
|
|
|
displayToasts([`Redirecting to: ${redirectURL}`], 'info');
|
|
|
|
// Redirect after 5 seconds
|
|
setTimeout(function() {
|
|
// Redirect the user
|
|
window.location.href = redirectURL;
|
|
}, 5000);
|
|
}
|
|
}
|
|
|
|
|
|
// Check for error messages
|
|
if (data.error_messages && data.error_messages.length > 0) {
|
|
displayToasts(data.error_messages, 'error');
|
|
|
|
// Check for the specific error message when domain is set and already has a valid ssl
|
|
if (data.error_messages.some(msg => msg.includes("Restarting the panel services to apply the newly generated SSL and force domain"))) {
|
|
// Handle the error condition
|
|
var portValue = document.querySelector('input[name="2087_port"]').value;
|
|
var server_hostname = "{{ server_hostname }}";
|
|
|
|
// Construct the redirect URL
|
|
var redirectURL = `https://${server_hostname}:${portValue}/settings/general`;
|
|
|
|
displayToasts([`Redirecting to: ${redirectURL}`], 'info');
|
|
|
|
// Redirect after 5 seconds
|
|
setTimeout(function() {
|
|
// Redirect the user
|
|
window.location.href = redirectURL;
|
|
}, 5000);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
})
|
|
.catch(error => console.error('Error:', error));
|
|
});
|
|
|
|
// Function to display Bootstrap Toasts
|
|
function displayToasts(messages, type) {
|
|
// Combine multiple messages into a single string
|
|
var combinedMessage = messages.join('<br>');
|
|
|
|
var toastDiv = document.createElement('div');
|
|
toastDiv.classList.add('toast');
|
|
toastDiv.setAttribute('role', 'alert');
|
|
toastDiv.setAttribute('aria-live', 'assertive');
|
|
toastDiv.setAttribute('aria-atomic', 'true');
|
|
|
|
toastDiv.innerHTML = `
|
|
<div class="toast-header">
|
|
<!-- Add SVG icons based on the message type -->
|
|
${type === 'success' ? successIcon : type === 'info' ? infoIcon : dangerIcon}
|
|
<strong class="me-auto">${type.charAt(0).toUpperCase() + type.slice(1)}</strong>
|
|
<small>${new Date().toLocaleTimeString()}</small>
|
|
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
</div>
|
|
<div class="toast-body">
|
|
${combinedMessage}
|
|
</div>
|
|
`;
|
|
|
|
toastContainer.appendChild(toastDiv);
|
|
|
|
// Use Bootstrap Toast to show the toast
|
|
var toast = new bootstrap.Toast(toastDiv);
|
|
toast.show();
|
|
}
|
|
|
|
// SVG icons for success and danger
|
|
var successIcon = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="green" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 12l5 5l10 -10"></path></svg>
|
|
`;
|
|
|
|
var infoIcon = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="blue" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg>
|
|
`;
|
|
|
|
var dangerIcon = `
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="red" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 8v4"></path><path d="M12 16h.01"></path></svg>
|
|
`;
|
|
});
|
|
|
|
|
|
|
|
// CHEKC FOR UPDATES
|
|
const versionUrl = 'https://update.openpanel.com/';
|
|
|
|
fetch(versionUrl)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.text();
|
|
})
|
|
.then(latestVersion => {
|
|
const localVersion = document.getElementById('local_version').textContent;
|
|
|
|
document.getElementById('latest_version').textContent = latestVersion;
|
|
document.getElementById('version_in_modal').textContent = latestVersion;
|
|
|
|
const changelogLink = document.getElementById('view_changelog');
|
|
changelogLink.href = `https://openpanel.com/docs/changelog/${latestVersion}`;
|
|
|
|
if (isVersionNewer(latestVersion, localVersion)) {
|
|
document.getElementById('update_is_available').style.display = 'flex';
|
|
document.getElementById('update_now_button').style.display = 'flex';
|
|
document.getElementById('view_changelog').style.display = 'inline';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('There was a problem with the fetch operation:', error);
|
|
});
|
|
|
|
function isVersionNewer(version1, version2) {
|
|
const v1 = version1.split('.').map(Number);
|
|
const v2 = version2.split('.').map(Number);
|
|
|
|
for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
|
|
const num1 = v1[i] || 0;
|
|
const num2 = v2[i] || 0;
|
|
|
|
if (num1 > num2) return true;
|
|
if (num1 < num2) return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
</script>
|
|
|
|
|
|
{% endblock %}
|