Finetuning software updates, general UI improvements

This commit is contained in:
“VeLiTi”
2026-01-13 14:35:16 +01:00
parent 0d3724395a
commit a0e1d386ad
46 changed files with 317 additions and 120 deletions

View File

@@ -35,6 +35,77 @@ if ($update_allowed === 1 && isset($_POST['submit'])) {
}
}
// Handle AJAX API requests
if (isset($_GET['action'])) {
$action = $_GET['action'];
// Suppress errors for API responses to avoid HTML output breaking JSON
error_reporting(0);
ini_set('display_errors', 0);
try {
// Licenses data
if ($action === 'licenses_data') {
// Filter out 'page', 'action', and cache busting timestamp from GET parameters
$filtered_params = $_GET;
unset($filtered_params['page']);
unset($filtered_params['action']);
unset($filtered_params['_t']);
$get_values = urlGETdetails($filtered_params) ?? '';
$api_url = '/v2/products_software_licenses/' . $get_values;
$response = ioServer($api_url, '');
header('Content-Type: application/json');
echo $response;
exit;
}
// Licenses totals
if ($action === 'licenses_totals') {
// Filter out 'page', 'action', and cache busting timestamp from GET parameters
$filtered_params = $_GET;
unset($filtered_params['page']);
unset($filtered_params['action']);
unset($filtered_params['_t']);
$get_values = urlGETdetails($filtered_params) ?? '';
$api_url = '/v2/products_software_licenses/' . $get_values . '&totals=';
$response = ioServer($api_url, '');
header('Content-Type: application/json');
echo $response;
exit;
}
// Software versions for dropdown
if ($action === 'software_versions') {
$api_url = '/v2/products_software_versions/list=&status=1';
$response = ioServer($api_url, '');
header('Content-Type: application/json');
echo $response;
exit;
}
// Handle license status update via AJAX
if ($action === 'update_license' && $_SERVER['REQUEST_METHOD'] === 'POST') {
if ($update_allowed === 1) {
$data = json_encode($_POST, JSON_UNESCAPED_UNICODE);
$response = ioServer('/v2/products_software_licenses', $data);
header('Content-Type: application/json');
echo json_encode(['success' => ($response !== 'NOK'), 'response' => $response]);
} else {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'error' => 'Not allowed']);
}
exit;
}
} catch (Exception $e) {
header('Content-Type: application/json');
echo json_encode(['error' => 'Server error', 'message' => $e->getMessage()]);
exit;
}
}
//GET PARAMETERS
$pagination_page = isset($_GET['p']) ? $_GET['p'] : 1;
$status = isset($_GET['status']) ? '&status='.$_GET['status'] : '';
@@ -197,7 +268,7 @@ $view .= '
<tr style="cursor: pointer;" onclick="openLicenseModal('.htmlspecialchars(json_encode($response), ENT_QUOTES).')">
<td>'.$response->license_key.'</td>
<td>'.$response->version_name.'</td>
<td><span class="status id'.$actual_status.'">'.$status_text.'</span></td>
<td>'.$status_text.'</td>
<td>'.($response->transaction_id ?? '-').'</td>
<td>'.$starts_display.'</td>
<td>'.$expires_display.'</td>
@@ -269,6 +340,17 @@ $view .= '
<input type="text" id="bulk_transaction_id" name="transaction_id" placeholder="e.g., PO-12345" required>
</div>
<div class="form-row">
<div class="form-group half">
<label for="bulk_starts_at">Start Date</label>
<input type="date" id="bulk_starts_at" name="starts_at">
</div>
<div class="form-group half">
<label for="bulk_expires_at">Expiration Date</label>
<input type="date" id="bulk_expires_at" name="expires_at">
</div>
</div>
<div class="form-actions">
<button type="button" onclick="closeBulkLicenseModal()" class="btn alt">Cancel</button>
<button type="submit" class="btn">Create Licenses</button>
@@ -312,13 +394,13 @@ $view .= '
</div>
<div class="detail-group">
<label style="display: block; margin-bottom: 5px; color: #666; font-size: 13px; font-weight: 500;">Starts At</label>
<div id="detail_starts_at" style="padding: 10px 12px; background: #f8f9fa; border-radius: 4px; font-size: 14px;"></div>
<label for="detail_starts_at" style="display: block; margin-bottom: 5px; color: #666; font-size: 13px; font-weight: 500;">Starts At</label>
<input type="date" id="detail_starts_at" name="starts_at" style="width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
</div>
<div class="detail-group">
<label style="display: block; margin-bottom: 5px; color: #666; font-size: 13px; font-weight: 500;">Expires</label>
<div id="detail_expires_at" style="padding: 10px 12px; background: #f8f9fa; border-radius: 4px; font-size: 14px;"></div>
<label for="detail_expires_at" style="display: block; margin-bottom: 5px; color: #666; font-size: 13px; font-weight: 500;">Expires</label>
<input type="date" id="detail_expires_at" name="expires_at" style="width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
</div>
<div class="detail-group" style="grid-column: 1 / -1;">
@@ -334,8 +416,11 @@ $view .= '
if ($update_allowed === 1) {
$view .= '
<button type="button" id="updateDatesBtn" class="btn" onclick="updateLicenseDates()">
<i class="fa-solid fa-save"></i>
</button>
<button type="submit" name="submit" id="setInactiveBtn" class="btn" style="background: #dc3545;" onclick="return confirm(\'Are you sure you want to set this license as inactive?\')">
<i class="fa-solid fa-ban"></i> Set Inactive
<i class="fa-solid fa-ban"></i>
</button>';
}
@@ -358,12 +443,21 @@ let currentLicenseData = null;
// Modal functions
function openBulkLicenseModal() {
// Set default dates
const today = new Date().toISOString().split(\'T\')[0];
document.getElementById("bulk_starts_at").value = today;
document.getElementById("bulk_expires_at").value = "2099-12-31";
document.getElementById("bulkLicenseModal").style.display = "flex";
}
function closeBulkLicenseModal() {
document.getElementById("bulkLicenseModal").style.display = "none";
document.getElementById("bulkLicenseForm").reset();
// Reset date fields to defaults
const today = new Date().toISOString().split(\'T\')[0];
document.getElementById("bulk_starts_at").value = today;
document.getElementById("bulk_expires_at").value = "2099-12-31";
}
// License detail modal functions
@@ -385,26 +479,25 @@ function openLicenseModal(licenseData) {
let statusClass = "";
if (actualStatus == 0) {
statusText = "Inactive";
statusClass = "id0";
statusClass = "id2";
} else if (actualStatus == 1) {
statusText = "Assigned";
statusClass = "id1";
} else if (actualStatus == 2) {
statusText = "Expired";
statusClass = "id2";
}
// Format dates
const startsDisplay = licenseData.starts_at ? new Date(licenseData.starts_at).toLocaleDateString() : "-";
const expiresDisplay = licenseData.expires_at ? new Date(licenseData.expires_at).toLocaleDateString() : "-";
// Format dates for input fields (YYYY-MM-DD)
const startsValue = licenseData.starts_at ? licenseData.starts_at.split(\' \')[0] : "";
const expiresValue = licenseData.expires_at ? licenseData.expires_at.split(\' \')[0] : "";
// Populate modal fields
document.getElementById("detail_license_key").textContent = licenseData.license_key || "-";
document.getElementById("detail_version_name").textContent = licenseData.version_name || "-";
document.getElementById("detail_status").innerHTML = \'<span class="status \' + statusClass + \'">\' + statusText + \'</span>\';
document.getElementById("detail_transaction_id").textContent = licenseData.transaction_id || "-";
document.getElementById("detail_starts_at").textContent = startsDisplay;
document.getElementById("detail_expires_at").textContent = expiresDisplay;
document.getElementById("detail_starts_at").value = startsValue;
document.getElementById("detail_expires_at").value = expiresValue;
document.getElementById("detail_assigned_serial").textContent = licenseData.assigned_serial || "-";
// Set hidden form field
@@ -462,24 +555,26 @@ document.getElementById("bulkLicenseForm").addEventListener("submit", async func
version_id: document.getElementById("bulk_version_id").value,
serials: serials,
transaction_id: document.getElementById("bulk_transaction_id").value,
license_type: 0,
status: 0
starts_at: document.getElementById("bulk_starts_at").value,
expires_at: document.getElementById("bulk_expires_at").value,
license_type: 1,
status: 1
};
try {
const response = await fetch("api.php/v2/products_software_licenses", {
const response = await fetch("index.php?page=licenses&action=update_license", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + sessionStorage.getItem("token")
"Content-Type": "application/x-www-form-urlencoded",
},
body: JSON.stringify(formData)
body: new URLSearchParams(formData)
});
if (response.ok) {
const result = await response.json();
if (result.success) {
window.location.href = "index.php?page=licenses&success_msg=1";
} else {
alert("Error creating licenses. Please try again.");
alert("Error creating licenses: " + (result.error || "Please try again."));
}
} catch (error) {
console.error("Error:", error);
@@ -496,6 +591,48 @@ function toggleFilters() {
panel.style.display = "none";
}
}
// Update license dates function
async function updateLicenseDates() {
const rowID = document.getElementById("detail_rowID").value;
const starts_at = document.getElementById("detail_starts_at").value;
const expires_at = document.getElementById("detail_expires_at").value;
if (!rowID) {
alert("Invalid license ID");
return;
}
// Convert date to timestamp format (YYYY-MM-DD HH:MM:SS)
const starts_at_timestamp = starts_at ? starts_at + " 00:00:00" : "";
const expires_at_timestamp = expires_at ? expires_at + " 23:59:59" : "";
const formData = {
rowID: rowID,
starts_at: starts_at_timestamp,
expires_at: expires_at_timestamp
};
try {
const response = await fetch("index.php?page=licenses&action=update_license", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams(formData)
});
const result = await response.json();
if (result.success) {
window.location.href = "index.php?page=licenses&success_msg=2";
} else {
alert("Error updating license: " + (result.error || "Please try again."));
}
} catch (error) {
console.error("Error:", error);
alert("Error updating license. Please try again.");
}
}
</script>
<style>
@@ -599,6 +736,17 @@ function toggleFilters() {
justify-content: flex-end;
margin-top: 25px;
}
.form-row {
display: flex;
gap: 15px;
margin-bottom: 20px;
}
.form-group.half {
flex: 1;
margin-bottom: 0;
}
</style>
';