Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6d1b654
Invoice: Do not apply late fee on first overdue reminder (day 1)
johnnyq Mar 20, 2026
22d3384
Fix edit client
johnnyq Mar 22, 2026
619dd0d
Fix missing csrf tokens in category modals
Mar 23, 2026
0e75106
Client POST: Added comment regarding MySQLi Prepared statement usage …
johnnyq Mar 23, 2026
65b53dd
Tables: Removed removed -sm in table-responsive to fix some responsiv…
johnnyq Mar 26, 2026
bb3e311
Racks: Fix Device Removal
johnnyq Mar 27, 2026
793b148
Remove unnecessary blank line in account.php
wrongecho Mar 30, 2026
35fb8b1
Update Changelog for 26.03.1 Release
johnnyq Mar 30, 2026
d8359e1
Network Interface Types: Moved to creatable/editable Categories with …
johnnyq Mar 30, 2026
7bed023
Categories: Make category type pretty Capitalize words, replace _ wit…
johnnyq Mar 30, 2026
383897e
Assets: Moved asset status to be creatable/editable Categories with c…
johnnyq Mar 30, 2026
11288ce
Fix missing setting DB Version
johnnyq Mar 30, 2026
aa19472
Ticket: Fix missing contact in version 1 Create Ticket
johnnyq Mar 30, 2026
5698da9
Update Changelog
johnnyq Mar 30, 2026
52eb0b9
Files: Allow .swb file extensions for MikroTik Backups
johnnyq Mar 31, 2026
02d2174
Categories: Moved note type, software type, rack type to be creatable…
johnnyq Mar 31, 2026
8591758
Fix asset read api - uri_2
Apr 4, 2026
52c2ba6
Don't set client ID from POST - this is properly done via require_pos…
Apr 4, 2026
9389f2c
More helpful error
Apr 4, 2026
0ae4c2f
- Prevent error 500s when existing data can't be cleanly re-inserted …
Apr 4, 2026
4617f44
- Prevent error 500s when existing data can't be cleanly re-inserted …
Apr 4, 2026
20be416
API
Apr 4, 2026
065e674
Quotes: Fix Quote Copy missing client
johnnyq Apr 4, 2026
4856c5c
Update Changelog
johnnyq Apr 4, 2026
c25b5aa
Update Changelog
johnnyq Apr 4, 2026
8a4bb2e
Update App version
johnnyq Apr 4, 2026
78971d1
Setup cli: add categories to mimic setup web ui
johnnyq Apr 4, 2026
e7ed88e
Remove custom_hosting tables from db.sql
johnnyq Apr 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,31 @@

This file documents all notable changes made to ITFlow.

## [26.04] Stable Release
### Bug Fixes
- Racks: Fix Device Removal.
- Table Lists: replace class table-responsive-sm with just table-reponsive was causing ui issues with certain screen sizes.
- Client: Fix Edit erroring on certain characters.
- Category: Fix Add/Edit due to missing CSRF fields.
- Invoice: Do not apply late fee on first overdue reminder (1 day).
- Ticket: Fix issue with contact not being added with Add contact modal v1.
- Quote: Fix Copy was missing client.
- API: Don't set client ID from POST - this is properly done via require_post_method instead only if it's an all-clients key.
- API: Prevent error 500s when existing data can't be cleanly re-inserted to database.
- API: Add more helpful errors.
- API: Fix asset read uri_2 field.
- API: Various other field fixes.

### New Features & Updates
- Categories: Add Description Field.
- Categories: Add DB Field for order.
- Categories: Move Asset Status and Network Interface Type to categories so custom ones can be created and edited.
- Categories: Moved note type, software type, rack type to be creatable/editable Categories with common defaults and descriptions
- Files: Allow .swb file for MikroTik Backup Files.

## [26.03] Stable Release
### Bug Fixes
- Ticket Templates: Fix Task Sorting.
- Ticket Templates: Fix Task Sortinhahahg.
- Ticket: Lower autoclose setting minimum value from 48 to 24 Hours.
- Ticket: Fix Task Approval.
- Recurring Ticket: add empty value placeholder for Ticket Frequency.
Expand Down
38 changes: 35 additions & 3 deletions admin/category.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@
<div class="card card-dark">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-list-ul mr-2"></i>
<?php echo nullable_htmlentities($category); ?> Categories
<?= nullable_htmlentities(ucwords(str_replace('_', ' ', $category))); ?> Categories
</h3>
<?php
if (!isset($_GET['archived'])) {
?>
<div class="card-tools">
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/category/category_add.php?category=<?= nullable_htmlentities($category) ?>"><i
class="fas fa-plus mr-2"></i>New <?php echo nullable_htmlentities($category); ?> Category</button>
class="fas fa-plus mr-2"></i>New <?= nullable_htmlentities(ucwords(str_replace('_', ' ', $category))); ?> Category</button>
</div>
<?php
}
Expand All @@ -51,7 +51,7 @@ class="fas fa-plus mr-2"></i>New <?php echo nullable_htmlentities($category); ?>
value="<?php if (isset($q)) {
echo stripslashes(nullable_htmlentities($q));
} ?>"
placeholder="Search <?php echo nullable_htmlentities($category); ?> Categories ">
placeholder="Search <?= nullable_htmlentities(ucwords(str_replace('_', ' ', $category))); ?> Categories ">
<div class="input-group-append">
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
</div>
Expand Down Expand Up @@ -83,6 +83,36 @@ class="btn <?php if ($category == 'Ticket') {
} else {
echo 'btn-default';
} ?>">Ticket</a>
<a href="?category=network_interface"
class="btn <?php if ($category == 'network_interface') {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Network Interface</a>
<a href="?category=asset_status"
class="btn <?php if ($category == 'asset_status') {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Asset Status</a>
<a href="?category=software_type"
class="btn <?php if ($category == 'software_type') {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Software Type</a>
<a href="?category=rack_type"
class="btn <?php if ($category == 'rack_type') {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Rack Type</a>
<a href="?category=contact_note_type"
class="btn <?php if ($category == 'contact_note_type') {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Contact Note Type</a>
<a href="?<?php echo $url_query_strings_sort ?>&archived=1"
class="btn <?php if (isset($_GET['archived'])) {
echo 'btn-primary';
Expand Down Expand Up @@ -114,6 +144,7 @@ class="fas fa-fw fa-archive mr-2"></i>Archived</a>
while ($row = mysqli_fetch_assoc($sql)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
$category_description = nullable_htmlentities($row['category_description']);
$category_color = nullable_htmlentities($row['category_color']);

?>
Expand All @@ -122,6 +153,7 @@ class="fas fa-fw fa-archive mr-2"></i>Archived</a>
<a class="text-dark ajax-modal" href="#"
data-modal-url="modals/category/category_edit.php?id=<?= $category_id ?>">
<?php echo $category_name; ?>
<div><small class="text-secondary"><?= $category_description ?></small></div>
</a>
</td>
<td><i class="fa fa-3x fa-circle" style="color:<?php echo $category_color; ?>;"></i></td>
Expand Down
67 changes: 63 additions & 4 deletions admin/database_updates.php
Original file line number Diff line number Diff line change
Expand Up @@ -4334,11 +4334,70 @@ function processFile($file_path, $file_name, $mysqli) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.2'");

}
//
// // if (CURRENT_DATABASE_VERSION == '2.4.2') {
// // Insert queries here required to update to DB version 2.4.3

if (CURRENT_DATABASE_VERSION == '2.4.2') {

mysqli_query($mysqli, "ALTER TABLE `categories` ADD `category_description` VARCHAR(255) DEFAULT NULL AFTER `category_name`");
mysqli_query($mysqli, "ALTER TABLE `categories` ADD `category_order` INT(11) NOT NULL DEFAULT 0 AFTER `category_icon`");

// Create network_interfaces
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Ethernet', category_type = 'network_interface', category_order = 1"); // 1
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'SFP', category_type = 'network_interface', category_order = 2"); // 2
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'SFP+', category_type = 'network_interface', category_order = 3"); // 3
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'QSFP28', category_type = 'network_interface', category_order = 4"); // 4
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'QSFP-DD', category_type = 'network_interface', category_order = 5"); // 5
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Coaxial', category_type = 'network_interface', category_order = 6"); // 6
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Fiber', category_type = 'network_interface', category_order = 7"); // 7
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'WiFi', category_type = 'network_interface', category_order = 8"); // 8



mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.3'");
}

if (CURRENT_DATABASE_VERSION == '2.4.3') {
// Asset Status
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Ready to Deploy', category_description = 'Asset is configured and ready to be assigned', category_type = 'asset_status', category_order = 1"); // 1
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Deployed', category_description = 'Asset is actively in use and assigned to a client or location', category_type = 'asset_status', category_order = 2"); // 2
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Out for Repair', category_description = 'Asset has been sent out for servicing or repair', category_type = 'asset_status', category_order = 3"); // 3
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Lost', category_description = 'Asset location is unknown and cannot be accounted for', category_type = 'asset_status', category_order = 4"); // 4
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Stolen', category_description = 'Asset has been reported stolen', category_type = 'asset_status', category_order = 5"); // 5
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Retired', category_description = 'Asset has been decommissioned and is no longer in service', category_type = 'asset_status', category_order = 6"); // 6

// Contact note types
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Call', category_description = 'Phone call with a client or contact', category_icon = 'fa-phone-alt', category_type = 'contact_note_type', category_order = 1"); // 1
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Email', category_description = 'Email correspondence with a client or contact', category_icon = 'fa-envelope', category_type = 'contact_note_type', category_order = 2"); // 2
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Meeting', category_description = 'Scheduled meeting with a client or contact', category_icon = 'fa-handshake', category_type = 'contact_note_type', category_order = 3"); // 3
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'In Person', category_description = 'In person visit or on-site interaction', category_icon = 'fa-people-arrows', category_type = 'contact_note_type', category_order = 4"); // 4
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Note', category_description = 'General note or internal comment', category_icon = 'fa-sticky-note', category_type = 'contact_note_type', category_order = 5"); // 5

// Rack Types
mysqli_query($mysqli, "INSERT INTO categories SET category_name = '2-Post Open Frame', category_description = 'Two-post open frame rack for patch panels and lightweight equipment', category_type = 'rack_type', category_order = 1"); // 1
mysqli_query($mysqli, "INSERT INTO categories SET category_name = '4-Post Open Frame', category_description = 'Four-post open frame rack for servers and heavier equipment', category_type = 'rack_type', category_order = 2"); // 2
mysqli_query($mysqli, "INSERT INTO categories SET category_name = '4-Post Enclosed Cabinet', category_description = 'Four-post enclosed cabinet with doors and sides for secure equipment housing', category_type = 'rack_type', category_order = 3"); // 3
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Wall-Mount Open', category_description = 'Open frame rack mounted directly to a wall for small deployments', category_type = 'rack_type', category_order = 4"); // 4
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Wall-Mount Enclosed', category_description = 'Enclosed cabinet rack mounted to a wall with a locking door', category_type = 'rack_type', category_order = 5"); // 5
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Other', category_description = 'Rack type does not fit any standard category', category_type = 'rack_type', category_order = 6"); // 6

// Software Types
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Software as a Service (SaaS)', category_description = 'Cloud-hosted software accessed via a web browser or API', category_type = 'software_type', category_order = 1"); // 1
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Productivity Suite', category_description = 'Bundled office and collaboration tools such as Microsoft 365 or Google Workspace', category_type = 'software_type', category_order = 2"); // 2
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Web Application', category_description = 'Application hosted on a web server and accessed through a browser', category_type = 'software_type', category_order = 3"); // 3
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Desktop Application', category_description = 'Application installed and run locally on a workstation or laptop', category_type = 'software_type', category_order = 4"); // 4
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Mobile Application', category_description = 'Application installed and run on a mobile device or tablet', category_type = 'software_type', category_order = 5"); // 5
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Security Software', category_description = 'Software providing antivirus, endpoint protection, or security monitoring', category_type = 'software_type', category_order = 6"); // 6
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'System Software', category_description = 'Low-level software managing hardware resources and system operations', category_type = 'software_type', category_order = 7"); // 7
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Operating System', category_description = 'Core software managing hardware and providing a platform for applications', category_type = 'software_type', category_order = 8"); // 8
mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Other', category_description = 'Software type does not fit any standard category', category_type = 'software_type', category_order = 9"); // 9

mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.4'");

}

// if (CURRENT_DATABASE_VERSION == '2.4.4') {
// // Insert queries here required to update to DB version 2.4.5
// // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.3'");
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.5'");
// }

} else {
Expand Down
13 changes: 12 additions & 1 deletion admin/modals/category/category_add.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
?>

<div class="modal-header bg-dark">
<h5 class="modal-title"><i class="fa fa-fw fa-list-ul mr-2"></i>New <strong><?= nullable_htmlentities($category) ?></strong> Category</h5>
<h5 class="modal-title"><i class="fa fa-fw fa-list-ul mr-2"></i>New <strong><?= nullable_htmlentities(ucwords(str_replace('_', ' ', $category))); ?></strong> Category</h5>
<button type="button" class="close text-white" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">

<div class="modal-body">

Expand Down Expand Up @@ -59,6 +60,16 @@
</div>
</div>

<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-fw fa-align-left"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Enter a description" maxlength="200">
</div>
</div>

</div>
<div class="modal-footer">
<button type="submit" name="add_category" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create Category</button>
Expand Down
12 changes: 12 additions & 0 deletions admin/modals/category/category_edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

$row = mysqli_fetch_assoc($sql);
$category_name = nullable_htmlentities($row['category_name']);
$category_description = nullable_htmlentities($row['category_description']);
$category_color = nullable_htmlentities($row['category_color']);
$category_type = nullable_htmlentities($row['category_type']);

Expand All @@ -21,6 +22,7 @@
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="category_id" value="<?php echo $category_id; ?>">
<input type="hidden" name="type" value="<?php echo $category_type; ?>">
<div class="modal-body">
Expand All @@ -45,6 +47,16 @@
</div>
</div>

<div class="form-group">
<label>Description</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-fw fa-align-left"></i></span>
</div>
<input type="text" class="form-control" name="description" placeholder="Enter a description" maxlength="200" value="<?= $category_description ?>">
</div>
</div>

</div>
<div class="modal-footer">
<button type="submit" name="edit_category" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button>
Expand Down
15 changes: 12 additions & 3 deletions admin/modals/software_template/software_template_add.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,18 @@
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="type" required>
<option value="">- Type -</option>
<?php foreach($software_types_array as $software_type) { ?>
<option><?php echo $software_type; ?></option>
<option value="">- Select Type -</option>
<<?php
$sql_software_types_select = mysqli_query($mysqli, "
SELECT category_name FROM categories
WHERE category_type = 'software_type'
AND category_archived_at IS NULL
ORDER BY category_order ASC, category_name ASC
");
while ($row = mysqli_fetch_assoc($sql_software_types_select)) {
$software_type_select = nullable_htmlentities($row['category_name']);
?>
<option><?= $software_type_select ?></option>
<?php } ?>
</select>
</div>
Expand Down
Loading
Loading