Feature: Favorites added to assets, Bulk Fav/unfav, adds favs to client overview

This commit is contained in:
johnnyq 2026-02-03 22:23:20 -05:00
parent f39e6ccbc9
commit 65d1f59e9b
14 changed files with 425 additions and 73 deletions

View File

@ -4154,10 +4154,49 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.9'");
}
// if (CURRENT_DATABASE_VERSION == '2.3.9') {
// // Insert queries here required to update to DB version 2.4.0
if (CURRENT_DATABASE_VERSION == '2.3.9') {
mysqli_query($mysqli, "ALTER TABLE `clients` ADD `client_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `client_notes`");
mysqli_query($mysqli, "ALTER TABLE `locations` ADD `location_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `location_notes`");
mysqli_query($mysqli, "ALTER TABLE `vendors` ADD `vendor_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `vendor_notes`");
mysqli_query($mysqli, "ALTER TABLE `software` ADD `software_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `software_notes`");
mysqli_query(
$mysqli,
"ALTER TABLE `credentials`
CHANGE `credential_important` `credential_favorite`
TINYINT(1) NOT NULL DEFAULT 0
AFTER `credential_note`"
);
mysqli_query($mysqli, "ALTER TABLE `assets` DROP `asset_important`");
mysqli_query($mysqli, "ALTER TABLE `assets` ADD `asset_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `asset_notes`");
mysqli_query($mysqli, "ALTER TABLE `documents` DROP `document_important`");
mysqli_query($mysqli, "ALTER TABLE `documents` ADD `document_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `document_client_visible`");
mysqli_query($mysqli, "ALTER TABLE `racks` ADD `rack_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `rack_notes`");
mysqli_query($mysqli, "ALTER TABLE `files` DROP `file_important`");
mysqli_query($mysqli, "ALTER TABLE `files` ADD `file_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `file_mime_type`");
mysqli_query($mysqli, "ALTER TABLE `networks` ADD `network_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `network_notes`");
mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `domain_notes`");
mysqli_query($mysqli, "ALTER TABLE `certificates` ADD `certificate_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `certificate_notes`");
mysqli_query($mysqli, "ALTER TABLE `services` ADD `service_favorite` TINYINT(1) NOT NULL DEFAULT '0' AFTER `service_notes`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.0'");
}
// if (CURRENT_DATABASE_VERSION == '2.4.0') {
// // Insert queries here required to update to DB version 2.4.1
// // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.0'");
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.1'");
// }
} else {

View File

@ -51,6 +51,7 @@ if (isset($_GET['asset_id'])) {
$asset_photo = nullable_htmlentities($row['asset_photo']);
$asset_physical_location = nullable_htmlentities($row['asset_physical_location']);
$asset_notes = nullable_htmlentities($row['asset_notes']);
$asset_favorite = intval($row['asset_favorite']);
$asset_created_at = nullable_htmlentities($row['asset_created_at']);
$asset_vendor_id = intval($row['asset_vendor_id']);
$asset_location_id = intval($row['asset_location_id']);
@ -226,7 +227,7 @@ if (isset($_GET['asset_id'])) {
credentials.credential_password,
credentials.credential_otp_secret,
credentials.credential_note,
credentials.credential_important,
credentials.credential_favorite,
credentials.credential_contact_id,
credentials.credential_asset_id
FROM credentials
@ -273,7 +274,9 @@ if (isset($_GET['asset_id'])) {
data-modal-url="modals/asset/asset_edit.php?id=<?= $asset_id ?>">
<i class="fas fa-fw fa-edit"></i>
</button>
<h4 class="text-bold"><i class="fa fa-fw text-secondary fa-<?= $device_icon; ?> mr-3"></i><?= $asset_name; ?></h4>
<h4 class="text-bold"><i class="fa fa-fw text-secondary fa-<?= $device_icon; ?> mr-2"></i><?= $asset_name; ?>
<?php if ($asset_favorite) { ?><i class="fas fa-fw text-warning fa-star" title="Favorite"></i><?php } ?>
</h4>
<?php if ($asset_photo) { ?>
<img class="img-fluid img-circle p-3" alt="asset_photo" src="<?= "../uploads/clients/$client_id/$asset_photo"; ?>">
<?php } ?>
@ -288,25 +291,25 @@ if (isset($_GET['asset_id'])) {
</div>
<?php } ?>
<?php if ($asset_type) { ?>
<div class="mt-1"><i class="fa fa-fw fa-tag text-secondary mr-3"></i><?= $asset_type; ?></div>
<div class="mt-1"><i class="fa fa-fw fa-tag text-secondary mr-2"></i><?= $asset_type; ?></div>
<?php }
if ($asset_make) { ?>
<div class="mt-2"><i class="fa fa-fw fa-circle text-secondary mr-3"></i><?= "$asset_make $asset_model"; ?></div>
<div class="mt-2"><i class="fa fa-fw fa-circle text-secondary mr-2"></i><?= "$asset_make $asset_model"; ?></div>
<?php }
if ($asset_os) { ?>
<div class="mt-2"><i class="fab fa-fw fa-windows text-secondary mr-3"></i><?= "$asset_os"; ?></div>
<div class="mt-2"><i class="fab fa-fw fa-windows text-secondary mr-2"></i><?= "$asset_os"; ?></div>
<?php }
if ($asset_serial) { ?>
<div class="mt-2"><i class="fa fa-fw fa-barcode text-secondary mr-3"></i><?= $asset_serial; ?></div>
<div class="mt-2"><i class="fa fa-fw fa-barcode text-secondary mr-2"></i><?= $asset_serial; ?></div>
<?php }
if ($asset_purchase_date) { ?>
<div class="mt-2"><i class="fa fa-fw fa-shopping-cart text-secondary mr-3"></i><?= date('Y-m-d', strtotime($asset_purchase_date)); ?></div>
<div class="mt-2"><i class="fa fa-fw fa-shopping-cart text-secondary mr-2"></i><?= date('Y-m-d', strtotime($asset_purchase_date)); ?></div>
<?php }
if ($asset_install_date) { ?>
<div class="mt-2"><i class="fa fa-fw fa-calendar-check text-secondary mr-3"></i><?= date('Y-m-d', strtotime($asset_install_date)); ?></div>
<div class="mt-2"><i class="fa fa-fw fa-calendar-check text-secondary mr-2"></i><?= date('Y-m-d', strtotime($asset_install_date)); ?></div>
<?php }
if ($asset_warranty_expire) { ?>
<div class="mt-2"><i class="fa fa-fw fa-exclamation-triangle text-secondary mr-3"></i><?= date('Y-m-d', strtotime($asset_warranty_expire)); ?></div>
<div class="mt-2"><i class="fa fa-fw fa-exclamation-triangle text-secondary mr-2"></i><?= date('Y-m-d', strtotime($asset_warranty_expire)); ?></div>
<?php } ?>
</div>
</div>
@ -657,7 +660,7 @@ if (isset($_GET['asset_id'])) {
$otp_display = "<span onmouseenter='showOTPViaCredentialID($credential_id)'><i class='far fa-clock'></i> <span id='otp_$credential_id'><i>Hover..</i></span></span>";
}
$credential_note = nullable_htmlentities($row['credential_note']);
$credential_important = intval($row['credential_important']);
$credential_favorite = intval($row['credential_favorite']);
$credential_contact_id = intval($row['credential_contact_id']);
$credential_asset_id = intval($row['credential_asset_id']);

View File

@ -345,6 +345,16 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount"></span>)
</button>
<div class="dropdown-menu">
<button class="dropdown-item"
type="submit" form="bulkActions" name="bulk_favorite_assets">
<i class="fas fa-fw fa-star text-warning mr-2"></i>Favorite
</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item"
type="submit" form="bulkActions" name="bulk_unfavorite_assets">
<i class="far fa-fw fa-star mr-2"></i>Unfavorite
</button>
<div class="dropdown-divider"></div>
<?php if ($client_url) { ?>
<a class="dropdown-item ajax-modal" href="#"
data-modal-url="modals/asset/asset_bulk_assign_contact.php?<?= $client_url ?>"
@ -590,6 +600,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$asset_physical_location_display = "";
}
$asset_notes = nullable_htmlentities($row['asset_notes']);
$asset_favorite = intval($row['asset_favorite']);
$asset_created_at = nullable_htmlentities($row['asset_created_at']);
$asset_archived_at = nullable_htmlentities($row['asset_archived_at']);
$asset_vendor_id = intval($row['asset_vendor_id']);
@ -660,7 +671,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div class="media">
<i class="fa fa-fw fa-2x fa-<?= $device_icon ?> mr-3 mt-1"></i>
<div class="media-body">
<div><?= $asset_name ?></div>
<div><?= $asset_name ?> <?php if ($asset_favorite) { echo "<i class='fas fa-fw fa-star text-warning' title='Favorite'></i>"; } ?></div>
<div><small class="text-secondary"><?= $asset_description ?></small></div>
<?php
if ($asset_tags_display) { ?>

View File

@ -23,6 +23,15 @@ $sql_important_contacts = mysqli_query(
ORDER BY contact_primary DESC, contact_name DESC LIMIT 5"
);
$sql_favorite_assets = mysqli_query(
$mysqli,
"SELECT * FROM assets
WHERE asset_client_id = $client_id
AND asset_favorite = 1
AND asset_archived_at IS NULL
ORDER BY asset_type ASC, asset_name ASC"
);
$sql_recent_tickets = mysqli_query(
$mysqli,
"SELECT * FROM tickets
@ -288,6 +297,45 @@ $sql_asset_retired = mysqli_query(
</div>
<div class="col-md-4">
<?php if (mysqli_num_rows($sql_favorite_assets) > 0) { ?>
<div class="card card-dark mb-3">
<div class="card-header">
<h5 class="card-title"><i class="fas fa-fw fa-star mr-2"></i>Favorite Assets</h5>
</div>
<div class="card-body p-2">
<table class="table table-borderless table-sm">
<?php
while ($row = mysqli_fetch_assoc($sql_favorite_assets)) {
$asset_id = intval($row['asset_id']);
$asset_name = nullable_htmlentities($row['asset_name']);
$asset_type = nullable_htmlentities($row['asset_type']);
$asset_icon = getAssetIcon($asset_type);
?>
<tr>
<td>
<a href="#" class="ajax-modal"
data-modal-size="lg"
data-modal-url="modals/asset/asset_details.php?id=<?= $asset_id ?>">
<i class="fas fa-fw fa-<?= $asset_icon ?> text-muted mr-2"></i><?= $asset_name ?>
</a>
</td>
</tr>
<?php
}
?>
</table>
</div>
</div>
<?php } ?>
</div>
<?php if (mysqli_num_rows($sql_shared_items) > 0) { ?>
<div class="col-md-4">

View File

@ -371,10 +371,10 @@ if (isset($_GET['contact_id'])) {
$asset_make = nullable_htmlentities($row['asset_make']);
$asset_model = nullable_htmlentities($row['asset_model']);
$asset_serial = nullable_htmlentities($row['asset_serial']);
if (empty($asset_serial)) {
$asset_serial_display = "-";
} else {
if ($asset_serial) {
$asset_serial_display = $asset_serial;
} else {
$asset_serial_display = "-";
}
$asset_os = nullable_htmlentities($row['asset_os']);
if (empty($asset_os)) {
@ -405,6 +405,7 @@ if (isset($_GET['contact_id'])) {
$asset_photo = nullable_htmlentities($row['asset_photo']);
$asset_physical_location = nullable_htmlentities($row['asset_physical_location']);
$asset_notes = nullable_htmlentities($row['asset_notes']);
$asset_favorite = intval($row['asset_favorite']);
$asset_created_at = nullable_htmlentities($row['asset_created_at']);
$device_icon = getAssetIcon($asset_type);
@ -433,14 +434,15 @@ if (isset($_GET['contact_id'])) {
?>
<tr>
<th>
<i class="fa fa-fw text-secondary fa-<?php echo $device_icon; ?> mr-2"></i>
<i class="fa fa-fw text-secondary fa-<?= $device_icon ?> mr-1"></i>
<a class="text-secondary ajax-modal" href="#"
data-modal-size="lg"
data-modal-url="modals/asset/asset_details.php?id=<?= $asset_id ?>">
<?php echo $asset_name; ?>
<?= $asset_name ?>
<?php if ($asset_favorite) { echo "<i class='fas fa-fw fa-star text-warning' title='Favorite'></i>"; } ?>
</a>
<div class="mt-0">
<small class="text-muted"><?php echo $asset_description; ?></small>
<small class="text-muted"><?= $asset_description ?></small>
</div>
<?php
if ($asset_tags_display) { ?>
@ -449,17 +451,17 @@ if (isset($_GET['contact_id'])) {
</div>
<?php } ?>
</th>
<td><?php echo $asset_type; ?></td>
<td><?= $asset_type ?></td>
<td>
<?php echo $asset_make; ?>
<?= $asset_make ?>
<div class="mt-0">
<small class="text-muted"><?php echo $asset_model; ?></small>
<small class="text-muted"><?= $asset_model ?></small>
</div>
</td>
<td><?php echo $asset_serial_display; ?></td>
<td><?= $asset_serial_display ?></td>
<td><?php echo $asset_install_date_display; ?></td>
<td><?php echo $asset_status; ?></td>
<td><?= $asset_install_date_display ?></td>
<td><?= $asset_status ?></td>
<td>
<div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown"><i class="fas fa-ellipsis-h"></i></button>
@ -474,16 +476,16 @@ if (isset($_GET['contact_id'])) {
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
href="post.php?unlink_asset_from_contact&contact_id=<?php echo $contact_id; ?>&asset_id=<?php echo $asset_id; ?>"
href="post.php?unlink_asset_from_contact&contact_id=<?= $contact_id ?>&asset_id=<?= $asset_id ?>"
class="btn btn-secondary btn-sm" title="Unlink">
<i class="fas fa-fw fa-unlink mr-2"></i>Unlink
</a>
<?php if ($session_user_role == 3) { ?>
<div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="post.php?archive_asset=<?php echo $asset_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<a class="dropdown-item text-danger" href="post.php?archive_asset=<?= $asset_id ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-archive mr-2"></i>Archive
</a>
<a class="dropdown-item text-danger text-bold" href="post.php?delete_asset=<?php echo $asset_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token'] ?>">
<a class="dropdown-item text-danger text-bold" href="post.php?delete_asset=<?= $asset_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
<i class="fas fa-fw fa-trash mr-2"></i>Delete
</a>
<?php } ?>
@ -557,7 +559,7 @@ if (isset($_GET['contact_id'])) {
$otp_display = "<span onmouseenter='showOTPViaCredentialID($credential_id)'><i class='far fa-clock'></i> <span id='otp_$credential_id'><i>Hover..</i></span></span>";
}
$credential_note = nullable_htmlentities($row['credential_note']);
$credential_important = intval($row['credential_important']);
$credential_favorite = intval($row['credential_favorite']);
$credential_contact_id = intval($row['credential_contact_id']);
$credential_asset_id = intval($row['credential_asset_id']);

View File

@ -98,12 +98,17 @@ ob_start();
<?php } ?>
<div class="form-group">
<label>Name <strong class="text-danger">*</strong></label>
<label>Name <strong class="text-danger">*</strong> / <span class="text-secondary" title="Pin to Overview">Favorite</span></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
<span class="input-group-text"><i class="fas fa-fw fa-tag"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Asset name or asset tag" maxlength="200" required autofocus>
<div class="input-group-append">
<div class="input-group-text">
<input type="checkbox" name="favortie" value="1">
</div>
</div>
</div>
</div>

View File

@ -35,6 +35,7 @@ $asset_install_date = nullable_htmlentities($row['asset_install_date']);
$asset_photo = nullable_htmlentities($row['asset_photo']);
$asset_physical_location = nullable_htmlentities($row['asset_physical_location']);
$asset_notes = nullable_htmlentities($row['asset_notes']);
$asset_favorite = intval($row['asset_favorite']);
$asset_created_at = nullable_htmlentities($row['asset_created_at']);
$asset_vendor_id = intval($row['asset_vendor_id']);
$asset_location_id = intval($row['asset_location_id']);
@ -145,7 +146,7 @@ $sql_related_credentials = mysqli_query($mysqli, "
credentials.credential_password,
credentials.credential_otp_secret,
credentials.credential_note,
credentials.credential_important,
credentials.credential_favorite,
credentials.credential_contact_id,
credentials.credential_asset_id
FROM credentials
@ -221,7 +222,9 @@ if (isset($_GET['client_id'])) {
ob_start();
?>
<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-<?php echo $device_icon; ?> mr-2"></i><strong><?php echo $asset_name; ?></strong></h5>
<h5 class="modal-title"><i class="fa fa-fw fa-<?= $device_icon ?> mr-2"></i><strong><?= $asset_name ?></strong>
<?php if ($asset_favorite) { ?><i class="fas fa-fw text-warning fa-star" title="Favorite"></i><?php } ?>
</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
@ -277,7 +280,9 @@ ob_start();
<div class="tab-pane fade show active" id="pills-asset-details<?php echo $asset_id; ?>">
<div class="card">
<div class="card-header">
<h3 class="text-bold"><i class="fa fa-fw text-secondary fa-<?php echo $device_icon; ?> mr-3"></i><?php echo $asset_name; ?></h3>
<h3 class="text-bold"><i class="fa fa-fw text-secondary fa-<?= $device_icon ?> mr-2"></i><?= $asset_name ?>
<?php if ($asset_favorite) { ?><i class="fas fa-fw text-warning fa-star" title="Favorite"></i><?php } ?>
</h3>
<?php if ($asset_photo) { ?>
<img class="img-fluid img-circle p-3" alt="asset_photo" src="<?php echo "../uploads/clients/$client_id/$asset_photo"; ?>">
<?php } ?>
@ -512,7 +517,7 @@ ob_start();
$otp_display = "<span onmouseenter='showOTPViaCredentialID($credential_id)'><i class='far fa-clock'></i> <span id='otp_$credential_id'><i>Hover..</i></span></span>";
}
$credential_note = nullable_htmlentities($row['credential_note']);
$credential_important = intval($row['credential_important']);
$credential_favorite = intval($row['credential_favorite']);
$credential_contact_id = intval($row['credential_contact_id']);
$credential_asset_id = intval($row['credential_asset_id']);

View File

@ -34,6 +34,7 @@ $asset_install_date = nullable_htmlentities($row['asset_install_date']);
$asset_photo = nullable_htmlentities($row['asset_photo']);
$asset_physical_location = nullable_htmlentities($row['asset_physical_location']);
$asset_notes = nullable_htmlentities($row['asset_notes']);
$asset_favorite = intval($row['asset_favorite']);
$asset_created_at = nullable_htmlentities($row['asset_created_at']);
$asset_archived_at = nullable_htmlentities($row['asset_archived_at']);
$asset_vendor_id = intval($row['asset_vendor_id']);
@ -105,9 +106,20 @@ ob_start();
<label>Name <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
<span class="input-group-text"><i class="fas fa-fw fa-tag"></i></span>
</div>
<input type="text" class="form-control" name="name" placeholder="Asset name or asset tag" maxlength="200" value="<?= $asset_name ?>" required>
<div class="input-group-append">
<div class="input-group-text">
<label class="star-toggle mb-0" title="Favorite">
<input type="checkbox"
name="favorite"
value="1"
<?php if($asset_favorite) { echo 'checked'; } ?>>
<i class="far fa-star"></i>
</label>
</div>
</div>
<input type="text" class="form-control" name="name" placeholder="Name the asset" maxlength="200" value="<?= $asset_name ?>" required>
</div>
</div>

View File

@ -478,14 +478,16 @@ ob_start();
$asset_tag_name_display_array[] = "<a href='assets.php?$client_url tags[]=$asset_tag_id'><span class='badge text-light p-1 mr-1' style='background-color: $asset_tag_color;'><i class='fa fa-fw fa-$asset_tag_icon mr-2'></i>$asset_tag_name</span></a>";
}
$asset_tags_display = implode('', $asset_tag_name_display_array);
$asset_favorite = intval($row['asset_favorite']);
?>
<tr>
<th>
<i class="fa fa-fw text-secondary fa-<?= $device_icon ?> mr-2"></i>
<a href="#" class="ajax-modal"
data-modal-size="lg"
data-modal-url="modals/asset/asset_details.php?id=<?= $asset_id ?>">
<?= $asset_name ?>
<i class="fa fa-fw text-secondary fa-<?= $device_icon ?> mr-2"></i><?= $asset_name ?>
<?php if ($asset_favorite) { echo "<i class='fas fa-fw fa-star text-warning' title='Favorite'></i>"; } ?>
</a>
<div class="mt-0">
<small class="text-muted"><?= $asset_description ?></small>

View File

@ -16,7 +16,7 @@ if (isset($_POST['add_asset'])) {
$alert_extended = "";
mysqli_query($mysqli,"INSERT INTO assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_uri_2 = '$uri_2', asset_uri_client = '$uri_client', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_status = '$status', asset_purchase_reference = '$purchase_reference', asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_physical_location = '$physical_location', asset_notes = '$notes', asset_client_id = $client_id");
mysqli_query($mysqli,"INSERT INTO assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_uri_2 = '$uri_2', asset_uri_client = '$uri_client', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_status = '$status', asset_purchase_reference = '$purchase_reference', asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_physical_location = '$physical_location', asset_notes = '$notes', asset_favorite = $favorite, asset_client_id = $client_id");
$asset_id = mysqli_insert_id($mysqli);
@ -88,7 +88,7 @@ if (isset($_POST['edit_asset'])) {
$row = mysqli_fetch_assoc($sql);
$existing_file_name = sanitizeInput($row['asset_photo']);
mysqli_query($mysqli,"UPDATE assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_uri_2 = '$uri_2', asset_uri_client = '$uri_client', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_status = '$status', asset_purchase_reference = '$purchase_reference', asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_physical_location = '$physical_location', asset_notes = '$notes' WHERE asset_id = $asset_id");
mysqli_query($mysqli,"UPDATE assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_uri_2 = '$uri_2', asset_uri_client = '$uri_client', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_status = '$status', asset_purchase_reference = '$purchase_reference', asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_physical_location = '$physical_location', asset_notes = '$notes', asset_favorite = $favorite WHERE asset_id = $asset_id");
$sql_interfaces = mysqli_query($mysqli, "SELECT * FROM asset_interfaces WHERE interface_asset_id = $asset_id AND interface_primary = 1");
@ -511,6 +511,78 @@ if (isset($_POST['bulk_edit_asset_status'])) {
}
if (isset($_POST['bulk_favorite_assets'])) {
validateCSRFToken($_POST['csrf_token']);
enforceUserPermission('module_support', 2);
if (isset($_POST['asset_ids'])) {
$count = count($_POST['asset_ids']);
foreach ($_POST['asset_ids'] as $asset_id) {
$asset_id = intval($asset_id);
// Get Asset Name and Client ID for logging and alert message
$sql = mysqli_query($mysqli,"SELECT asset_name, asset_client_id FROM assets WHERE asset_id = $asset_id");
$row = mysqli_fetch_assoc($sql);
$asset_name = sanitizeInput($row['asset_name']);
$client_id = intval($row['asset_client_id']);
mysqli_query($mysqli,"UPDATE assets SET asset_favorite = 1 WHERE asset_id = $asset_id");
logAction("Asset", "Edit", "$session_name marked asset $asset_name a favorite", $client_id, $asset_id);
}
logAction("Asset", "Bulk Edit", "$session_name favorited $count assets", $client_id);
flash_alert("Favorited <strong>$count</strong> asset(s)");
}
redirect();
}
if (isset($_POST['bulk_unfavorite_assets'])) {
validateCSRFToken($_POST['csrf_token']);
enforceUserPermission('module_support', 2);
if (isset($_POST['asset_ids'])) {
$count = count($_POST['asset_ids']);
foreach ($_POST['asset_ids'] as $asset_id) {
$asset_id = intval($asset_id);
// Get Asset Name and Client ID for logging and alert message
$sql = mysqli_query($mysqli,"SELECT asset_name, asset_client_id FROM assets WHERE asset_id = $asset_id");
$row = mysqli_fetch_assoc($sql);
$asset_name = sanitizeInput($row['asset_name']);
$client_id = intval($row['asset_client_id']);
mysqli_query($mysqli,"UPDATE assets SET asset_favorite = 0 WHERE asset_id = $asset_id");
logAction("Asset", "Edit", "$session_name unfavorited asset $asset_name", $client_id, $asset_id);
}
logAction("Asset", "Bulk Edit", "$session_name unfavorited $count assets", $client_id);
flash_alert("Unfavorited <strong>$count</strong> asset(s)");
}
redirect();
}
if (isset($_POST['bulk_archive_assets'])) {
validateCSRFToken($_POST['csrf_token']);

View File

@ -45,4 +45,5 @@ if (empty($install_date)) {
$install_date = "'" . $install_date . "'";
}
$notes = sanitizeInput($_POST['notes']);
$favorite = intval($_POST['favorite'] ?? 0);
$client_id = intval($_POST['client_id']);

View File

@ -1,6 +1,6 @@
/*
For screens below 576px (xs):
- Make the button full-width, display:block
/*
For screens below 576px (xs):
- Make the button full-width, display:block
*/
@media (max-width: 575.98px) {
.btn-responsive {
@ -9,9 +9,9 @@
}
}
/*
/*
For screens 576px (sm) and above:
- Revert to an inline style
- Revert to an inline style
*/
@media (min-width: 576px) {
.btn-responsive {
@ -26,4 +26,19 @@
.drag-handle:active {
cursor: grabbing !important;
}
}
.star-toggle input {
display: none;
}
.star-toggle i {
cursor: pointer;
font-size: 1.2rem;
color: #adb5bd;
}
.star-toggle input:checked + i {
color: #f1c40f;
font-weight: 900;
}

185
db.sql
View File

@ -319,7 +319,7 @@ CREATE TABLE `assets` (
`asset_photo` varchar(200) DEFAULT NULL,
`asset_physical_location` varchar(200) DEFAULT NULL,
`asset_notes` text DEFAULT NULL,
`asset_important` tinyint(1) NOT NULL DEFAULT 0,
`asset_favorite` tinyint(1) NOT NULL DEFAULT 0,
`asset_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`asset_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`asset_archived_at` datetime DEFAULT NULL,
@ -496,6 +496,7 @@ CREATE TABLE `certificates` (
`certificate_expire` date DEFAULT NULL,
`certificate_public_key` mediumtext DEFAULT NULL,
`certificate_notes` mediumtext DEFAULT NULL,
`certificate_favorite` tinyint(1) NOT NULL DEFAULT 0,
`certificate_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`certificate_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`certificate_archived_at` datetime DEFAULT NULL,
@ -607,6 +608,7 @@ CREATE TABLE `clients` (
`client_tax_id_number` varchar(255) DEFAULT NULL,
`client_abbreviation` varchar(10) DEFAULT NULL,
`client_notes` text DEFAULT NULL,
`client_favorite` tinyint(1) NOT NULL DEFAULT 0,
`client_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`client_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`client_archived_at` datetime DEFAULT NULL,
@ -902,7 +904,7 @@ CREATE TABLE `credentials` (
`credential_password` varbinary(200) DEFAULT NULL,
`credential_otp_secret` varchar(200) DEFAULT NULL,
`credential_note` text DEFAULT NULL,
`credential_important` tinyint(1) NOT NULL DEFAULT 0,
`credential_favorite` tinyint(1) NOT NULL DEFAULT 0,
`credential_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`credential_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`credential_archived_at` datetime DEFAULT NULL,
@ -958,6 +960,132 @@ CREATE TABLE `custom_fields` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_api_keys`
--
DROP TABLE IF EXISTS `custom_hosting_api_keys`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_api_keys` (
`api_key_id` int(11) NOT NULL AUTO_INCREMENT,
`api_key_name` varchar(200) NOT NULL,
`api_key_url` varchar(250) NOT NULL,
`api_key_token_id` varchar(200) NOT NULL,
`api_key_token_secret` varchar(250) NOT NULL,
`api_key_created_at` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`api_key_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_networks`
--
DROP TABLE IF EXISTS `custom_hosting_networks`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_networks` (
`network_id` int(11) NOT NULL AUTO_INCREMENT,
`network_name` varchar(200) NOT NULL,
`network` varchar(100) NOT NULL,
`network_mask` varchar(100) NOT NULL,
`gateway` varchar(100) NOT NULL,
`network_start` varchar(100) NOT NULL,
`network_end` varchar(100) NOT NULL,
PRIMARY KEY (`network_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_plans`
--
DROP TABLE IF EXISTS `custom_hosting_plans`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_plans` (
`plan_id` int(11) NOT NULL AUTO_INCREMENT,
`plan_name` varchar(250) NOT NULL,
`plan_description` text NOT NULL,
`plan_created_at` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`plan_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_regions`
--
DROP TABLE IF EXISTS `custom_hosting_regions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_regions` (
`region_id` int(11) NOT NULL AUTO_INCREMENT,
`region_name` varchar(200) NOT NULL,
`region_created_at` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`region_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_servers`
--
DROP TABLE IF EXISTS `custom_hosting_servers`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_servers` (
`server_id` int(11) NOT NULL AUTO_INCREMENT,
`server_node` varchar(200) NOT NULL,
`server_storage` varchar(200) NOT NULL,
`server_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`server_region_id` int(11) NOT NULL,
`server_api_key_id` varchar(200) NOT NULL,
PRIMARY KEY (`server_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_vm_templates`
--
DROP TABLE IF EXISTS `custom_hosting_vm_templates`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_vm_templates` (
`template_id` int(11) NOT NULL AUTO_INCREMENT,
`template_name` varchar(200) NOT NULL,
`vcpus` int(11) NOT NULL,
`memory` int(11) NOT NULL,
`disk` int(11) NOT NULL,
`template_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`template_plan_id` int(11) NOT NULL,
PRIMARY KEY (`template_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_hosting_vms`
--
DROP TABLE IF EXISTS `custom_hosting_vms`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `custom_hosting_vms` (
`vm_id` int(11) NOT NULL AUTO_INCREMENT,
`vm_hostname` varchar(200) NOT NULL,
`vm_ip` varchar(100) NOT NULL,
`vm_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`vm_network_id` int(11) NOT NULL,
`vm_server_id` int(11) NOT NULL,
`vm_template_id` int(11) NOT NULL,
`vm_recurring_invoice_id` int(11) DEFAULT NULL,
`vm_client_id` int(11) NOT NULL,
PRIMARY KEY (`vm_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `custom_links`
--
@ -1087,8 +1215,8 @@ CREATE TABLE `documents` (
`document_description` text DEFAULT NULL,
`document_content` longtext NOT NULL,
`document_content_raw` longtext NOT NULL,
`document_important` tinyint(1) NOT NULL DEFAULT 0,
`document_client_visible` int(11) NOT NULL DEFAULT 1,
`document_favorite` tinyint(1) NOT NULL DEFAULT 0,
`document_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`document_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`document_archived_at` datetime DEFAULT NULL,
@ -1140,6 +1268,7 @@ CREATE TABLE `domains` (
`domain_txt` text DEFAULT NULL,
`domain_raw_whois` text DEFAULT NULL,
`domain_notes` text DEFAULT NULL,
`domain_favorite` tinyint(1) NOT NULL DEFAULT 0,
`domain_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`domain_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`domain_archived_at` datetime DEFAULT NULL,
@ -1220,7 +1349,7 @@ CREATE TABLE `files` (
`file_ext` varchar(10) DEFAULT NULL,
`file_size` bigint(20) unsigned NOT NULL DEFAULT 0,
`file_mime_type` varchar(100) DEFAULT NULL,
`file_important` tinyint(1) NOT NULL DEFAULT 0,
`file_favorite` tinyint(1) NOT NULL DEFAULT 0,
`file_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`file_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`file_archived_at` datetime DEFAULT NULL,
@ -1370,6 +1499,7 @@ CREATE TABLE `locations` (
`location_photo` varchar(200) DEFAULT NULL,
`location_primary` tinyint(1) NOT NULL DEFAULT 0,
`location_notes` text DEFAULT NULL,
`location_favorite` tinyint(1) NOT NULL DEFAULT 0,
`location_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`location_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`location_archived_at` datetime DEFAULT NULL,
@ -1436,6 +1566,7 @@ CREATE TABLE `networks` (
`network_secondary_dns` varchar(200) DEFAULT NULL,
`network_dhcp_range` varchar(200) DEFAULT NULL,
`network_notes` text DEFAULT NULL,
`network_favorite` tinyint(1) NOT NULL DEFAULT 0,
`network_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`network_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`network_archived_at` datetime DEFAULT NULL,
@ -1722,6 +1853,7 @@ CREATE TABLE `racks` (
`rack_photo` varchar(200) DEFAULT NULL,
`rack_physical_location` varchar(200) DEFAULT NULL,
`rack_notes` text DEFAULT NULL,
`rack_favorite` tinyint(1) NOT NULL DEFAULT 0,
`rack_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`rack_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`rack_archived_at` datetime DEFAULT NULL,
@ -2055,6 +2187,7 @@ CREATE TABLE `services` (
`service_importance` varchar(10) NOT NULL,
`service_backup` varchar(200) DEFAULT NULL,
`service_notes` mediumtext NOT NULL,
`service_favorite` tinyint(1) NOT NULL DEFAULT 0,
`service_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`service_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`service_accessed_at` datetime DEFAULT NULL,
@ -2209,6 +2342,7 @@ CREATE TABLE `software` (
`software_purchase` date DEFAULT NULL,
`software_expire` date DEFAULT NULL,
`software_notes` text DEFAULT NULL,
`software_favorite` tinyint(1) NOT NULL DEFAULT 0,
`software_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`software_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`software_archived_at` datetime DEFAULT NULL,
@ -2399,6 +2533,27 @@ CREATE TABLE `tags` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `task_approvals`
--
DROP TABLE IF EXISTS `task_approvals`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `task_approvals` (
`approval_id` int(11) NOT NULL AUTO_INCREMENT,
`approval_scope` enum('client','internal') NOT NULL,
`approval_type` enum('any','technical','billing','specific') NOT NULL,
`approval_required_user_id` int(11) DEFAULT NULL,
`approval_status` enum('pending','approved','declined') NOT NULL,
`approval_created_by` int(11) NOT NULL,
`approval_approved_by` varchar(255) DEFAULT NULL,
`approval_url_key` varchar(200) NOT NULL,
`approval_task_id` int(11) NOT NULL,
PRIMARY KEY (`approval_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `task_templates`
--
@ -2441,25 +2596,6 @@ CREATE TABLE `tasks` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `task_approvals`
--
DROP TABLE IF EXISTS `task_approvals`;
CREATE TABLE IF NOT EXISTS `task_approvals` (
`approval_id` int(11) NOT NULL AUTO_INCREMENT,
`approval_scope` enum('client','internal') NOT NULL,
`approval_type` enum('any','technical','billing','specific') NOT NULL,
`approval_required_user_id` int(11) DEFAULT NULL,
`approval_status` enum('pending','approved','declined') NOT NULL,
`approval_created_by` int(11) NOT NULL,
`approval_approved_by` varchar(255) DEFAULT NULL,
`approval_url_key` varchar(200) NOT NULL,
`approval_task_id` int(11) NOT NULL,
PRIMARY KEY (`approval_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `taxes`
--
@ -2913,6 +3049,7 @@ CREATE TABLE `vendors` (
`vendor_code` varchar(200) DEFAULT NULL,
`vendor_account_number` varchar(200) DEFAULT NULL,
`vendor_notes` text DEFAULT NULL,
`vendor_favorite` tinyint(1) NOT NULL DEFAULT 0,
`vendor_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`vendor_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`vendor_archived_at` datetime DEFAULT NULL,
@ -2932,4 +3069,4 @@ CREATE TABLE `vendors` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-11-11 19:57:21
-- Dump completed on 2026-02-03 22:22:07

View File

@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php
*/
DEFINE("LATEST_DATABASE_VERSION", "2.3.9");
DEFINE("LATEST_DATABASE_VERSION", "2.4.0");