Refactor software version update logic into a reusable function; enhance UI for file uploads and table responsiveness
This commit is contained in:
@@ -161,25 +161,8 @@ if ($sw_version_latest_update == 1){
|
||||
//------------------------------------------
|
||||
//UPDATE SW_STATUS
|
||||
//------------------------------------------
|
||||
//UPDATE ASSETS-> SW_LATEST_VERSION WITH NO PRODUCT_SOFTWARE TO 2
|
||||
$sql = 'UPDATE equipment e LEFT JOIN products_software ps ON e.productrowid = ps.productrowid SET e.sw_version_latest = 2 WHERE ps.rowID IS NULL';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
|
||||
//UPDATE ASSETS-> SW_LATEST_VERSION WITH PRODUCT_SOFTWARE FROM 2 TO 0
|
||||
$sql = 'UPDATE equipment e LEFT JOIN products_software ps ON e.productrowid = ps.productrowid SET e.sw_version_latest = 0 WHERE ps.rowID IS NOT NULL AND sw_version_latest = 2';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
|
||||
//UPDATE LATEST TO NO IN CASE HW_VERSION ARE EQUAL AND SW_VERSIONS NOT AND NOT LATEST
|
||||
$sql = 'UPDATE equipment e JOIN products_software ps ON e.productrowid = ps.productrowid SET e.sw_version_latest = 0 WHERE ps.latest = 1 AND lower(e.sw_version) <> lower(ps.version) AND lower(e.hw_version) = lower(ps.hw_version) AND e.sw_version_latest = 1';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
|
||||
//UPDATE LATEST TO YES IN CASE HW_VERSION ARE EQUAL AND SW_VERSIONS ARE EQUAL
|
||||
$sql = 'UPDATE equipment e JOIN products_software ps ON e.productrowid = ps.productrowid SET e.sw_version_latest = 1 WHERE ps.latest = 1 AND lower(e.sw_version) = lower(ps.version) AND lower(e.hw_version) = lower(ps.hw_version) AND e.sw_version_latest = 0';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute();
|
||||
// Use the reusable function to update software version status for all equipment
|
||||
updateSoftwareVersionStatus($pdo);
|
||||
//------------------------------------------
|
||||
//------------------------------------------
|
||||
}
|
||||
|
||||
@@ -5112,3 +5112,83 @@ function checkAndInsertIdentityDealer($pdo, $identityUserkey) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
// Update software version status for equipment
|
||||
// Parameters:
|
||||
// $pdo - PDO database connection
|
||||
// $serialnumber - Optional serial number. If null, updates all equipment
|
||||
// Returns: boolean - true on success, false on error
|
||||
//------------------------------------------
|
||||
function updateSoftwareVersionStatus($pdo, $serialnumber = null) {
|
||||
try {
|
||||
// Build WHERE clause for serial number filtering if provided
|
||||
$sn_clause = '';
|
||||
$bind_params = [];
|
||||
|
||||
if ($serialnumber !== null) {
|
||||
$sn_clause = ' AND e.serialnumber = ?';
|
||||
$bind_params = [$serialnumber];
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
// STEP 1: Set sw_version_latest = 2 for equipment with NO software assignments
|
||||
//------------------------------------------
|
||||
$sql = 'UPDATE equipment e
|
||||
LEFT JOIN products_software_assignment psa ON e.productrowid = psa.product_id AND psa.status = 1
|
||||
SET e.sw_version_latest = 2
|
||||
WHERE psa.product_id IS NULL' . $sn_clause;
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($bind_params);
|
||||
|
||||
//------------------------------------------
|
||||
// STEP 2: Set sw_version_latest = 0 for equipment WITH software assignments (from previous 2)
|
||||
//------------------------------------------
|
||||
$sql = 'UPDATE equipment e
|
||||
JOIN products_software_assignment psa ON e.productrowid = psa.product_id AND psa.status = 1
|
||||
SET e.sw_version_latest = 0
|
||||
WHERE e.sw_version_latest = 2' . $sn_clause;
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($bind_params);
|
||||
|
||||
//------------------------------------------
|
||||
// STEP 3: Set sw_version_latest = 0 for equipment NOT matching latest version
|
||||
//------------------------------------------
|
||||
$sql = 'UPDATE equipment e
|
||||
JOIN products_software_assignment psa ON e.productrowid = psa.product_id AND psa.status = 1
|
||||
JOIN products_software_versions psv ON psa.software_version_id = psv.rowID
|
||||
SET e.sw_version_latest = 0
|
||||
WHERE psv.latest = 1
|
||||
AND psv.status = 1
|
||||
AND lower(e.sw_version) <> lower(psv.version)
|
||||
AND (psv.hw_version = e.hw_version OR psv.hw_version IS NULL OR psv.hw_version = "")
|
||||
AND e.sw_version_latest = 1' . $sn_clause;
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($bind_params);
|
||||
|
||||
//------------------------------------------
|
||||
// STEP 4: Set sw_version_latest = 1 for equipment matching latest version
|
||||
//------------------------------------------
|
||||
$sql = 'UPDATE equipment e
|
||||
JOIN products_software_assignment psa ON e.productrowid = psa.product_id AND psa.status = 1
|
||||
JOIN products_software_versions psv ON psa.software_version_id = psv.rowID
|
||||
SET e.sw_version_latest = 1
|
||||
WHERE psv.latest = 1
|
||||
AND psv.status = 1
|
||||
AND lower(e.sw_version) = lower(psv.version)
|
||||
AND (psv.hw_version = e.hw_version OR psv.hw_version IS NULL OR psv.hw_version = "")
|
||||
AND e.sw_version_latest = 0' . $sn_clause;
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($bind_params);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log('Database error in updateSoftwareVersionStatus: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ $filter_version_id = $_GET['from_version_id'] ?? $_GET['to_version_id'] ?? $_GET
|
||||
if (isset($_GET['id']) && $_GET['id'] != '') {
|
||||
$api_url = '/v2/products_software_upgrade_paths/rowID=' . $_GET['id'];
|
||||
$response = ioServer($api_url, '');
|
||||
var_dump($response);
|
||||
|
||||
if (!empty($response)) {
|
||||
$existing = json_decode($response);
|
||||
if (!empty($existing)) {
|
||||
@@ -145,7 +145,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$api_url = '/v2/products_software_upgrade_paths/';
|
||||
$result = ioServer($api_url, json_encode($data));
|
||||
|
||||
if ($result) {
|
||||
if ($result !== 'NOK') {
|
||||
$success = isset($_POST['delete']) ? 3 : (isset($_POST['rowID']) && $_POST['rowID'] != '' ? 2 : 1);
|
||||
header('Location: ' . $url . '&success_msg=' . $success);
|
||||
exit;
|
||||
|
||||
@@ -143,7 +143,6 @@ $view = '
|
||||
<th>Currency</th>
|
||||
<th>Description</th>
|
||||
<th>Active</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -151,18 +150,17 @@ $view = '
|
||||
|
||||
$all_paths = array_merge($upgrade_paths_from ?: [], $upgrade_paths_to ?: []);
|
||||
if (empty($all_paths)){
|
||||
$view .= '<tr><td colspan="7">No upgrade paths found.</td></tr>';
|
||||
$view .= '<tr><td colspan="6">No upgrade paths found.</td></tr>';
|
||||
} else {
|
||||
foreach ($all_paths as $path){
|
||||
$view .= '
|
||||
<tr>
|
||||
<tr onclick="window.location.href=\'index.php?page=products_software_upgrade_paths_manage&id='.$path->rowID.'\'" style="cursor: pointer;">
|
||||
<td>' . ($version_map[$path->from_version_id] ?? $path->from_version_id) . '</td>
|
||||
<td>' . ($version_map[$path->to_version_id] ?? $path->to_version_id) . '</td>
|
||||
<td>'.$path->price.'</td>
|
||||
<td>'.$path->currency.'</td>
|
||||
<td>'.$path->description.'</td>
|
||||
<td>'.($path->is_active ? 'Yes' : 'No').'</td>
|
||||
<td><a href="index.php?page=products_software_upgrade_paths_manage&id='.$path->rowID.'" class="btn_link">Edit</a></td>
|
||||
</tr>
|
||||
';
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$api_url = '/v2/products_software_versions/';
|
||||
$result = ioServer($api_url, json_encode($data));
|
||||
|
||||
if ($result) {
|
||||
if ($result !== 'NOK') {
|
||||
$success = isset($_POST['delete']) ? 3 : (isset($_POST['rowID']) && $_POST['rowID'] != '' ? 2 : 1);
|
||||
header('Location: ' . $url . '&success_msg=' . $success);
|
||||
exit;
|
||||
@@ -147,7 +147,14 @@ $view .= '<div class="content-block">
|
||||
<label for="hw_version">HW Version</label>
|
||||
<input id="hw_version" type="text" name="hw_version" placeholder="HW Version" value="' . htmlspecialchars($version['hw_version']) . '">
|
||||
<label for="fileToUpload">Upload File</label>
|
||||
<input type="file" name="fileToUpload" id="fileToUpload" onchange="updateFields()">
|
||||
<div class="file-upload-wrapper">
|
||||
<button type="button" class="file-upload-btn" onclick="document.getElementById(\'fileToUpload\').click()">
|
||||
<i class="fas fa-cloud-upload-alt"></i>
|
||||
<span id="uploadBtnText">Choose File</span>
|
||||
</button>
|
||||
<input type="file" name="fileToUpload" id="fileToUpload" style="display: none;" onchange="updateFields()" accept=".hex,.bin,.fw">
|
||||
<span class="file-upload-info" id="fileUploadInfo">No file selected</span>
|
||||
</div>
|
||||
<label for="file_path">File Path</label>
|
||||
<input id="file_path" type="text" name="file_path" placeholder="File Path" value="' . htmlspecialchars($version['file_path']) . '" readonly>
|
||||
<label class="checkbox">
|
||||
@@ -164,7 +171,10 @@ $view .= '<div class="content-block">
|
||||
<script>
|
||||
function updateFields() {
|
||||
var fileInput = document.getElementById(\'fileToUpload\');
|
||||
var uploadBtnText = document.getElementById(\'uploadBtnText\');
|
||||
var fileUploadInfo = document.getElementById(\'fileUploadInfo\');
|
||||
var file = fileInput.files[0];
|
||||
|
||||
if (file) {
|
||||
var fileName = file.name;
|
||||
var filePathInput = document.getElementById(\'file_path\');
|
||||
@@ -175,8 +185,25 @@ function updateFields() {
|
||||
var nameWithoutExt = fileName.replace(/\.[^/.]+$/, "");
|
||||
versionInput.value = nameWithoutExt;
|
||||
}
|
||||
|
||||
// Update button and info text
|
||||
uploadBtnText.textContent = \'Change File\';
|
||||
fileUploadInfo.textContent = fileName + \' (\' + formatFileSize(file.size) + \')\';
|
||||
fileUploadInfo.style.color = \'#28a745\';
|
||||
} else {
|
||||
uploadBtnText.textContent = \'Choose File\';
|
||||
fileUploadInfo.textContent = \'No file selected\';
|
||||
fileUploadInfo.style.color = \'#6c757d\';
|
||||
}
|
||||
}
|
||||
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return \'0 Bytes\';
|
||||
const k = 1024;
|
||||
const sizes = [\'Bytes\', \'KB\', \'MB\', \'GB\'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \' \' + sizes[i];
|
||||
}
|
||||
</script>
|
||||
';
|
||||
|
||||
|
||||
70
profiles.php
70
profiles.php
@@ -298,46 +298,52 @@ $view .= '</form>';
|
||||
// Add basic JavaScript functionality
|
||||
$view .= '
|
||||
<style>
|
||||
.profile-content { display: none !important; }
|
||||
.profile-content { display: none; }
|
||||
.profile-content.active { display: block !important; }
|
||||
.profile-tab { background: #f8f9fa; color: #333; }
|
||||
.profile-tab.active { background: #007bff; color: white; }
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// Use the working tab functionality from admin.js
|
||||
document.querySelectorAll(\'.profile-tab\').forEach((element, index) => {
|
||||
element.onclick = event => {
|
||||
event.preventDefault();
|
||||
|
||||
// Ensure all tabs start inactive
|
||||
document.querySelectorAll(".profile-tab").forEach(tab => {
|
||||
tab.classList.remove("active");
|
||||
});
|
||||
document.querySelectorAll(".profile-content").forEach(content => {
|
||||
content.style.display = "none";
|
||||
// Toggle the clicked tab
|
||||
const isActive = element.classList.contains(\'active\');
|
||||
const profileId = element.dataset.profile;
|
||||
const tabContent = document.getElementById(profileId + \'-content\');
|
||||
|
||||
// Remove active class from all tabs and contents
|
||||
document.querySelectorAll(\'.profile-tab\').forEach(el => el.classList.remove(\'active\'));
|
||||
document.querySelectorAll(\'.profile-content\').forEach(content => {
|
||||
content.classList.remove(\'active\');
|
||||
content.style.display = \'none\';
|
||||
});
|
||||
|
||||
// Tab functionality
|
||||
document.addEventListener("click", function(e) {
|
||||
if (e.target.classList.contains("profile-tab")) {
|
||||
e.preventDefault();
|
||||
|
||||
// Hide all content
|
||||
document.querySelectorAll(".profile-content").forEach(content => {
|
||||
content.style.display = "none";
|
||||
});
|
||||
|
||||
// Remove active class from all tabs
|
||||
document.querySelectorAll(".profile-tab").forEach(t => {
|
||||
t.classList.remove("active");
|
||||
});
|
||||
|
||||
// Show selected content and mark tab as active
|
||||
const profileId = e.target.dataset.profile;
|
||||
const content = document.getElementById(profileId + "-content");
|
||||
if (content) {
|
||||
content.style.display = "block";
|
||||
e.target.classList.add("active");
|
||||
}
|
||||
// If it wasn\'t active, make it active (collapsible behavior)
|
||||
if (!isActive && tabContent) {
|
||||
element.classList.add(\'active\');
|
||||
tabContent.classList.add(\'active\');
|
||||
tabContent.style.display = \'block\';
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Bulk select functionality
|
||||
// Initialize first tab as open by default
|
||||
if (document.querySelectorAll(\'.profile-tab\').length > 0) {
|
||||
const firstTab = document.querySelectorAll(\'.profile-tab\')[0];
|
||||
const profileId = firstTab.dataset.profile;
|
||||
const firstContent = document.getElementById(profileId + \'-content\');
|
||||
if (firstTab && firstContent) {
|
||||
firstTab.classList.add(\'active\');
|
||||
firstContent.classList.add(\'active\');
|
||||
firstContent.style.display = \'block\';
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk select functionality
|
||||
document.addEventListener("click", function(e) {
|
||||
if (e.target.classList.contains("select-all")) {
|
||||
const profile = e.target.dataset.profile;
|
||||
const checkboxes = document.querySelectorAll("[name=\\"" + profile + "[]\\"]");
|
||||
@@ -349,8 +355,6 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
const checkboxes = document.querySelectorAll("[name=\\"" + profile + "[]\\"]");
|
||||
checkboxes.forEach(cb => cb.checked = false);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>';
|
||||
|
||||
|
||||
@@ -3006,4 +3006,83 @@ main .products .product .price, main .products .products-wrapper .product .price
|
||||
.filter-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Fix table scrolling on smaller screens */
|
||||
main .content-block {
|
||||
overflow: visible !important;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
main .content-block .table {
|
||||
overflow-x: auto !important;
|
||||
overflow-y: visible !important;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
max-width: 100%;
|
||||
margin: 0 -10px; /* Extend to container edges */
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
main .content-block .table table {
|
||||
min-width: 700px; /* Ensure table maintains minimum width */
|
||||
width: max-content; /* Allow table to expand naturally */
|
||||
}
|
||||
|
||||
/* Ensure table cells don't wrap */
|
||||
main .content-block .table table td,
|
||||
main .content-block .table table th {
|
||||
white-space: nowrap;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
/* Make version columns wider as they contain longer text */
|
||||
main .content-block .table table th:first-child,
|
||||
main .content-block .table table td:first-child,
|
||||
main .content-block .table table th:nth-child(2),
|
||||
main .content-block .table table td:nth-child(2) {
|
||||
min-width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
/* File Upload Button Styles */
|
||||
.file-upload-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.file-upload-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 10px;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
|
||||
}
|
||||
|
||||
.file-upload-btn:hover {
|
||||
background: linear-gradient(135deg, #0056b3, #004085);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
|
||||
}
|
||||
|
||||
.file-upload-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
|
||||
}
|
||||
|
||||
.file-upload-btn i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.file-upload-info {
|
||||
font-size: 12px;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
}
|
||||
Reference in New Issue
Block a user