From 38efc6290036f95aaacc2e13d40e071e8dc8a42b Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Thu, 6 Mar 2025 16:01:46 +0000
Subject: [PATCH 01/13] Add index on action_date, copy from created_at

Signed-off-by: snipe <snipe@snipe.net>
---
 app/Models/Actionlog.php                      |  6 ++++
 ...eated_at_to_action_date_in_action_logs.php | 31 +++++++++++++++++++
 2 files changed, 37 insertions(+)
 create mode 100644 database/migrations/2025_03_06_152922_copy_created_at_to_action_date_in_action_logs.php

diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php
index a14910208ea7..67f30701c3e1 100755
--- a/app/Models/Actionlog.php
+++ b/app/Models/Actionlog.php
@@ -93,7 +93,13 @@ public static function boot()
             } elseif (auth()->user() && auth()->user()->company) {
                 $actionlog->company_id = auth()->user()->company_id;
             }
+
+            if ($actionlog->action_date == '') {
+                $actionlog->action_date = Carbon::now();
+            }
+
         });
+
     }
 
 
diff --git a/database/migrations/2025_03_06_152922_copy_created_at_to_action_date_in_action_logs.php b/database/migrations/2025_03_06_152922_copy_created_at_to_action_date_in_action_logs.php
new file mode 100644
index 000000000000..8ce7de13bdf6
--- /dev/null
+++ b/database/migrations/2025_03_06_152922_copy_created_at_to_action_date_in_action_logs.php
@@ -0,0 +1,31 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+
+        Schema::table('action_logs', function (Blueprint $table) {
+            $table->index(['action_date']);
+        });
+
+        DB::update('update '.DB::getTablePrefix().'action_logs set action_date = created_at where created_at IS NOT NULL and action_date IS NULL');
+
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+
+    }
+};

From 4e3df93349f3b1894ccb7b3eb741b087be7efea0 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Thu, 6 Mar 2025 16:16:17 +0000
Subject: [PATCH 02/13] Change action_date display to date from datetime

Signed-off-by: snipe <snipe@snipe.net>
---
 app/Http/Transformers/ActionlogsTransformer.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php
index 702ea123d8f2..04a7861d40d3 100644
--- a/app/Http/Transformers/ActionlogsTransformer.php
+++ b/app/Http/Transformers/ActionlogsTransformer.php
@@ -201,7 +201,7 @@ public function transformActionlog (Actionlog $actionlog, $settings = null)
             'remote_ip'          => ($actionlog->remote_ip) ??  null,
             'user_agent'          => ($actionlog->user_agent) ??  null,
             'action_source'          => ($actionlog->action_source) ??  null,
-            'action_date'   => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
+            'action_date'   => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'date'): Helper::getFormattedDateObject($actionlog->created_at, 'date'),
         ];
 
 //        Log::info("Clean Meta is: ".print_r($clean_meta,true));

From d4dc8d2b79021e17843d730271e0a8dd5e0cb6f6 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Thu, 6 Mar 2025 17:43:07 +0000
Subject: [PATCH 03/13] Remove action_date from loggable as a changed field

Signed-off-by: snipe <snipe@snipe.net>
---
 app/Models/Loggable.php | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php
index 1e4a9120274c..f2fdd192f83d 100644
--- a/app/Models/Loggable.php
+++ b/app/Models/Loggable.php
@@ -89,13 +89,10 @@ public function logCheckout($note, $target, $action_date = null, $originalValues
         $log->note = $note;
         $log->action_date = $action_date;
 
-        if (! $log->action_date) {
-            $log->action_date = date('Y-m-d H:i:s');
-        }
 
         $changed = [];
         $array_to_flip = array_keys($fields_array);
-        $array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
+        $array_to_flip = array_merge($array_to_flip, ['name','status_id','location_id','expected_checkin']);
         $originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
 
 
@@ -191,7 +188,7 @@ public function logCheckin($target, $note, $action_date = null, $originalValues
         $changed = [];
 
         $array_to_flip = array_keys($fields_array);
-        $array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
+        $array_to_flip = array_merge($array_to_flip, ['name','status_id','location_id','expected_checkin']);
 
         $originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
 

From 80a69bfe90bb42b43c8af2bc966abc9cbbe9a26b Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Thu, 6 Mar 2025 18:09:27 +0000
Subject: [PATCH 04/13] Revert datetime to date

Signed-off-by: snipe <snipe@snipe.net>
---
 app/Http/Transformers/ActionlogsTransformer.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php
index 04a7861d40d3..702ea123d8f2 100644
--- a/app/Http/Transformers/ActionlogsTransformer.php
+++ b/app/Http/Transformers/ActionlogsTransformer.php
@@ -201,7 +201,7 @@ public function transformActionlog (Actionlog $actionlog, $settings = null)
             'remote_ip'          => ($actionlog->remote_ip) ??  null,
             'user_agent'          => ($actionlog->user_agent) ??  null,
             'action_source'          => ($actionlog->action_source) ??  null,
-            'action_date'   => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'date'): Helper::getFormattedDateObject($actionlog->created_at, 'date'),
+            'action_date'   => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
         ];
 
 //        Log::info("Clean Meta is: ".print_r($clean_meta,true));

From c825878c46d9981b9d8048912853c006d71bf5aa Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 10:57:33 +0000
Subject: [PATCH 05/13] Added history presenter

Signed-off-by: snipe <snipe@snipe.net>
---
 app/Presenters/HistoryPresenter.php | 146 ++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100644 app/Presenters/HistoryPresenter.php

diff --git a/app/Presenters/HistoryPresenter.php b/app/Presenters/HistoryPresenter.php
new file mode 100644
index 000000000000..543d840bc9fd
--- /dev/null
+++ b/app/Presenters/HistoryPresenter.php
@@ -0,0 +1,146 @@
+<?php
+
+namespace App\Presenters;
+
+/**
+ * Class AccessoryPresenter
+ */
+class HistoryPresenter extends Presenter
+{
+    /**
+     * Json Column Layout for bootstrap table
+     * @return string
+     */
+    public static function dataTableLayout()
+    {
+        $layout = [
+            [
+                'field' => 'icon',
+                'searchable' => false,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('admin/hardware/table.icon'),
+                'visible' => true,
+                'class' => 'hidden-xs',
+                'formatter' => 'iconFormatter',
+            ],
+            [
+                'field' => 'created_at',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.created_at'),
+                'visible' => false,
+                'formatter' => 'dateDisplayFormatter',
+            ],
+            [
+                'field' => 'created_by',
+                'searchable' => false,
+                'sortable' => true,
+                'title' => trans('general.created_by'),
+                'visible' => false,
+                'formatter' => 'usersLinkObjFormatter',
+            ],
+            [
+                'field' => 'action_date',
+                'searchable' => false,
+                'sortable' => true,
+                'title' => trans('general.action_date'),
+                'visible' => false,
+                'formatter' => 'dateDisplayFormatter',
+            ],
+            [
+                'field' => 'action_type',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.action'),
+                'visible' => false,
+            ],
+            [
+                'field' => 'item',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.item'),
+                'visible' => false,
+                'formatter' => 'polymorphicItemFormatter',
+            ], [
+                'field' => 'target',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.target'),
+                'visible' => false,
+                'formatter' => 'polymorphicItemFormatter',
+            ],
+            [
+                'field' => 'file',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.file_name'),
+                'visible' => false,
+                'formatter' => 'fileUploadNameFormatter',
+            ],
+            [
+                'field' => 'file_download',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.download'),
+                'visible' => false,
+                'formatter' => 'fileUploadFormatter',
+            ],
+            [
+                'field' => 'note',
+                'searchable' => true,
+                'sortable' => true,
+                'visible' => false,
+                'title' => trans('general.notes'),
+                'formatter' => 'notesFormatter'
+            ],
+            [
+                'field' => 'signature_file',
+                'searchable' => true,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.signature'),
+                'visible' => false,
+                'formatter' => 'imageFormatter',
+            ],
+            [
+                'field' => 'log_meta',
+                'searchable' => false,
+                'sortable' => false,
+                'visible' => true,
+                'title' => trans('admin/hardware/table.changed'),
+                'formatter' => 'changeLogFormatter',
+            ],
+            [
+                'field' => 'remote_ip',
+                'searchable' => false,
+                'sortable' => false,
+                'visible' => true,
+                'title' => trans('admin/settings/general.login_ip'),
+            ],
+            [
+                'field' => 'user_agent',
+                'searchable' => false,
+                'sortable' => false,
+                'visible' => true,
+                'title' => trans('admin/settings/general.login_user_agent'),
+            ],
+            [
+                'field' => 'action_source',
+                'searchable' => false,
+                'sortable' => false,
+                'visible' => true,
+                'title' => trans('general.action_source'),
+            ],
+        ];
+
+        return json_encode($layout);
+    }
+
+}
\ No newline at end of file

From 55694fa2fc94deb6a17740673fdc92fe4887ad07 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 10:57:40 +0000
Subject: [PATCH 06/13] Added strings

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/lang/en-US/general.php | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/resources/lang/en-US/general.php b/resources/lang/en-US/general.php
index 8366a68216e7..3c5de482dc2e 100644
--- a/resources/lang/en-US/general.php
+++ b/resources/lang/en-US/general.php
@@ -8,9 +8,11 @@
     'accessory'				=> 'Accessory',
     'accessory_report'		=> 'Accessory Report',
     'action'                => 'Action',
+    'action_date'			=> 'Action Date',
     'activity_report'		=> 'Activity Report',
     'address'				=> 'Address',
     'admin'					=> 'Admin Settings',
+    'admin_user'			=> 'Admin User',
     'admin_tooltip'			=> 'This user has admin privileges',
     'superuser'				=> 'Superuser',
     'superuser_tooltip'		=> 'This user has superuser privileges',

From 7ba361b10df12fda099bd40b04a12b142b4f7740 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 10:57:54 +0000
Subject: [PATCH 07/13] Use date formatter for filestable

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/views/blade/filestable.blade.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/resources/views/blade/filestable.blade.php b/resources/views/blade/filestable.blade.php
index e198e339dae1..1c9aa7217545 100644
--- a/resources/views/blade/filestable.blade.php
+++ b/resources/views/blade/filestable.blade.php
@@ -120,7 +120,7 @@ class="table table-striped snipe-table"
                     @endif
                 </td>
                 <td>
-                    {{ $file->created_at }}
+                    {{ $file->created_at ? Helper::getFormattedDateObject($file->created_at, 'datetime', false) : '' }}
                 </td>
                 <td>
                     {{ ($file->adminuser) ? $file->adminuser->present()->getFullNameAttribute() : '' }}

From cb7822576fb7277d89492d8143d4ad51ab604f7c Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 11:48:19 +0000
Subject: [PATCH 08/13] Use new presenters

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/views/accessories/view.blade.php | 34 ++++++++++++++++------
 resources/views/consumables/view.blade.php | 21 ++-----------
 resources/views/hardware/view.blade.php    | 19 +-----------
 3 files changed, 28 insertions(+), 46 deletions(-)

diff --git a/resources/views/accessories/view.blade.php b/resources/views/accessories/view.blade.php
index 8042b4ec5164..c7f3ddc7a1dc 100644
--- a/resources/views/accessories/view.blade.php
+++ b/resources/views/accessories/view.blade.php
@@ -106,6 +106,7 @@ class="table table-striped snipe-table"
                              <div class="row">
                                  <div class="col-md-12">
                                 <table
+                                        data-columns="{{ \App\Presenters\HistoryPresenter::assignedDataTableLayout() }}"
                                         class="table table-striped snipe-table"
                                         data-cookie-id-table="AccessoryHistoryTable"
                                         data-id-table="AccessoryHistoryTable"
@@ -124,16 +125,31 @@ class="table table-striped snipe-table"
 
                                             <thead>
                                             <tr>
-                                                <th class="col-sm-2" data-visible="false" data-sortable="true" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.record_created') }}</th>
-                                                <th class="col-sm-2"data-visible="true" data-sortable="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
-                                                <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
-                                                <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">{{ trans('general.file_name') }}</th>
-                                                <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
-                                                <th class="col-sm-2" data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
-                                                <th class="col-sm-2" data-sortable="true" data-visible="true" data-field="note">{{ trans('general.notes') }}</th>
-                                                <th class="col-sm-2" data-visible="true" data-field="action_date" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
+                                                <th class="col-sm-2" data-visible="false" data-sortable="true" data-field="created_at" data-formatter="dateDisplayFormatter">
+                                                    {{ trans('general.date') }}
+                                                </th>
+                                                <th class="col-sm-2" data-visible="true" data-sortable="true" data-field="admin" data-formatter="usersLinkObjFormatter">
+                                                    {{ trans('general.admin_user') }}
+                                                </th>
+                                                <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="action_type">
+                                                    {{ trans('general.action') }}
+                                                </th>
+                                                <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">
+                                                    {{ trans('general.file_name') }}
+                                                </th>
+                                                <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">
+                                                    {{ trans('general.item') }}
+                                                </th>
+                                                <th class="col-sm-2" data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">
+                                                    {{ trans('general.target') }}
+                                                </th>
+                                                <th class="col-sm-2" data-sortable="true" data-visible="true" data-field="note">
+                                                    {{ trans('general.notes') }}
+                                                </th>
                                                 @if  ($snipeSettings->require_accept_signature=='1')
-                                                    <th class="col-md-3" data-field="signature_file" data-visible="false"  data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
+                                                    <th class="col-md-3" data-field="signature_file" data-visible="false"  data-formatter="imageFormatter">
+                                                        {{ trans('general.signature') }}
+                                                    </th>
                                                 @endif
                                             </tr>
                                             </thead>
diff --git a/resources/views/consumables/view.blade.php b/resources/views/consumables/view.blade.php
index ac95e6391b26..0a340765bfb4 100644
--- a/resources/views/consumables/view.blade.php
+++ b/resources/views/consumables/view.blade.php
@@ -446,6 +446,7 @@ class="table table-striped snipe-table"
             <div class="table-responsive">
 
               <table
+                      data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout() }}"
                       class="table table-striped snipe-table"
                       id="consumableHistory"
                       data-pagination="true"
@@ -464,26 +465,8 @@ class="table table-striped snipe-table"
                        }'
 
                       data-url="{{ route('api.activity.index', ['item_id' => $consumable->id, 'item_type' => 'consumable']) }}"
-                      data-cookie-id-table="assetHistory"
+                      data-cookie-id-table="consumableHistory"
                       data-cookie="true">
-                <thead>
-                <tr>
-                  <th data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">{{ trans('admin/hardware/table.icon') }}</th>
-                  <th data-visible="true" data-field="action_date" data-sortable="true" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
-                  <th data-visible="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
-                  <th data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
-                  <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">{{ trans('general.file_name') }}</th>
-                  <th data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
-                  <th data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
-                  <th data-field="note">{{ trans('general.notes') }}</th>
-                  <th data-field="signature_file" data-visible="false"  data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
-                  <th data-visible="false" data-field="file" data-visible="false"  data-formatter="fileUploadFormatter">{{ trans('general.download') }}</th>
-                  <th data-field="log_meta" data-visible="true" data-formatter="changeLogFormatter">{{ trans('admin/hardware/table.changed')}}</th>
-                  <th data-field="remote_ip" data-visible="false" data-sortable="true">{{ trans('admin/settings/general.login_ip') }}</th>
-                  <th data-field="user_agent" data-visible="false" data-sortable="true">{{ trans('admin/settings/general.login_user_agent') }}</th>
-                  <th data-field="action_source" data-visible="false" data-sortable="true">{{ trans('general.action_source') }}</th>
-                </tr>
-                </thead>
               </table>
             </div>
           </div><!-- /.tab-pane -->
diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php
index a59b0534b2a7..dc37e8a62bfe 100755
--- a/resources/views/hardware/view.blade.php
+++ b/resources/views/hardware/view.blade.php
@@ -1389,6 +1389,7 @@ class="table table-striped snipe-table"
                         <div class="row">
                             <div class="col-md-12">
                                 <table
+                                        data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout() }}"
                                         class="table table-striped snipe-table"
                                         id="assetHistory"
                                         data-pagination="true"
@@ -1409,24 +1410,6 @@ class="table table-striped snipe-table"
                                         data-url="{{ route('api.activity.index', ['item_id' => $asset->id, 'item_type' => 'asset']) }}"
                                         data-cookie-id-table="assetHistory"
                                         data-cookie="true">
-                                    <thead>
-                                    <tr>
-                                        <th data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">{{ trans('admin/hardware/table.icon') }}</th>
-                                        <th data-visible="true" data-field="action_date" data-sortable="true" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
-                                        <th data-visible="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
-                                        <th data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
-                                        <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">{{ trans('general.file_name') }}</th>
-                                        <th data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
-                                        <th data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
-                                        <th data-field="note">{{ trans('general.notes') }}</th>
-                                        <th data-field="signature_file" data-visible="false"  data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
-                                        <th data-visible="false" data-field="file" data-visible="false"  data-formatter="fileUploadFormatter">{{ trans('general.download') }}</th>
-                                        <th data-field="log_meta" data-visible="true" data-formatter="changeLogFormatter">{{ trans('admin/hardware/table.changed')}}</th>
-                                        <th data-field="remote_ip" data-visible="false" data-sortable="true">{{ trans('admin/settings/general.login_ip') }}</th>
-                                        <th data-field="user_agent" data-visible="false" data-sortable="true">{{ trans('admin/settings/general.login_user_agent') }}</th>
-                                        <th data-field="action_source" data-visible="false" data-sortable="true">{{ trans('general.action_source') }}</th>
-                                    </tr>
-                                    </thead>
                                 </table>
                             </div>
                         </div> <!-- /.row -->

From ef56177372afedf0b0e3243205d23843afb99d23 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 11:48:31 +0000
Subject: [PATCH 09/13] Use presenter

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/views/licenses/view.blade.php | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/resources/views/licenses/view.blade.php b/resources/views/licenses/view.blade.php
index 2de0f9d6e0bc..b827e34217a5 100755
--- a/resources/views/licenses/view.blade.php
+++ b/resources/views/licenses/view.blade.php
@@ -479,6 +479,7 @@ class="table table-striped snipe-table"
             <div class="col-md-12">
               <div class="table-responsive">
               <table
+                      data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout() }}"
                       class="table table-striped snipe-table"
                       data-cookie-id-table="licenseHistoryTable"
                       data-id-table="licenseHistoryTable"
@@ -494,22 +495,6 @@ class="table table-striped snipe-table"
                        "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
                      }'
                       data-url="{{ route('api.activity.index', ['item_id' => $license->id, 'item_type' => 'license']) }}">
-
-                <thead>
-                <tr>
-                  <th class="col-sm-2" data-visible="false" data-sortable="true" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.record_created') }}</th>
-                  <th class="col-sm-2"data-visible="true" data-sortable="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
-                  <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
-                  <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">{{ trans('general.file_name') }}</th>
-                  <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
-                  <th class="col-sm-2" data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
-                  <th class="col-sm-2" data-sortable="true" data-visible="true" data-field="note">{{ trans('general.notes') }}</th>
-                  <th class="col-sm-2" data-visible="true" data-field="action_date" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
-                  @if  ($snipeSettings->require_accept_signature=='1')
-                    <th class="col-md-3" data-field="signature_file" data-visible="false"  data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
-                  @endif
-                </tr>
-                </thead>
               </table>
               </div>
             </div> <!-- /.col-md-12-->

From 92b2da9b1b8c59b0f6bd0b8619a548f739c4dae8 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 11:48:38 +0000
Subject: [PATCH 10/13] Added history tab to components

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/views/components/view.blade.php | 39 +++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/resources/views/components/view.blade.php b/resources/views/components/view.blade.php
index f090b9566563..db059641a226 100644
--- a/resources/views/components/view.blade.php
+++ b/resources/views/components/view.blade.php
@@ -67,6 +67,16 @@
           </a>
         </li>
 
+        <li>
+          <a href="#history" data-toggle="tab">
+                <span class="hidden-lg hidden-md">
+                  <i class="fas fa-history fa-2x" aria-hidden="true"></i>
+                </span>
+            <span class="hidden-xs hidden-sm">
+                  {{ trans('general.history') }}
+                </span>
+          </a>
+        </li>
 
         @can('components.files', $component)
           <li>
@@ -137,6 +147,35 @@ class="table table-striped snipe-table"
           </div>
         </div> <!-- close tab-pane div -->
 
+        <div class="tab-pane" id="history">
+          <div class="table-responsive">
+
+            <table
+                    data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout() }}"
+                    class="table table-striped snipe-table"
+                    id="componentHistory"
+                    data-pagination="true"
+                    data-id-table="componentHistory"
+                    data-search="true"
+                    data-side-pagination="server"
+                    data-show-columns="true"
+                    data-show-fullscreen="true"
+                    data-show-refresh="true"
+                    data-sort-order="desc"
+                    data-sort-name="created_at"
+                    data-show-export="true"
+                    data-export-options='{
+                         "fileName": "export-component-{{  $component->id }}-history",
+                         "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
+                       }'
+
+                    data-url="{{ route('api.activity.index', ['item_id' => $component->id, 'item_type' => 'component']) }}"
+                    data-cookie-id-table="componentHistory"
+                    data-cookie="true">
+            </table>
+          </div>
+        </div><!-- /.tab-pane -->
+
 
         @can('components.files', $component)
           <div class="tab-pane" id="files">

From df5437647b40c422a918696c26006c17f107d2df Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 12:43:38 +0000
Subject: [PATCH 11/13] Add optional serial value in presenter

Signed-off-by: snipe <snipe@snipe.net>
---
 app/Presenters/HistoryPresenter.php        | 34 +++++++++++++--
 resources/views/reports/activity.blade.php | 51 +---------------------
 2 files changed, 31 insertions(+), 54 deletions(-)

diff --git a/app/Presenters/HistoryPresenter.php b/app/Presenters/HistoryPresenter.php
index 543d840bc9fd..3b90dff31a2c 100644
--- a/app/Presenters/HistoryPresenter.php
+++ b/app/Presenters/HistoryPresenter.php
@@ -11,9 +11,19 @@ class HistoryPresenter extends Presenter
      * Json Column Layout for bootstrap table
      * @return string
      */
-    public static function dataTableLayout()
+    public static function dataTableLayout($serial = false)
     {
-        $layout = [
+        $extra = [];
+        $layout_start = [
+            [
+                'id' => 'id',
+                'searchable' => false,
+                'sortable' => true,
+                'switchable' => true,
+                'title' => trans('general.id'),
+                'visible' => false,
+                'class' => 'hidden-xs',
+            ],
             [
                 'field' => 'icon',
                 'searchable' => false,
@@ -65,7 +75,22 @@ public static function dataTableLayout()
                 'title' => trans('general.item'),
                 'visible' => false,
                 'formatter' => 'polymorphicItemFormatter',
-            ], [
+            ],
+        ];
+
+
+        if ($serial) {
+            $extra =  [
+                [
+                'field' => 'item.serial',
+                'title' => trans('admin/hardware/table.serial'),
+                'visible' => false,
+            ]
+            ];
+        }
+
+        $layout_end = [
+            [
                 'field' => 'target',
                 'searchable' => true,
                 'sortable' => true,
@@ -140,7 +165,8 @@ public static function dataTableLayout()
             ],
         ];
 
-        return json_encode($layout);
+        $merged = array_merge($layout_start, $extra, $layout_end);
+        return json_encode($merged);
     }
 
 }
\ No newline at end of file
diff --git a/resources/views/reports/activity.blade.php b/resources/views/reports/activity.blade.php
index c8f789ec7692..f671e114a8ca 100644
--- a/resources/views/reports/activity.blade.php
+++ b/resources/views/reports/activity.blade.php
@@ -25,6 +25,7 @@
             <div class="box-body">
 
                 <table
+                        data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout($serial = true) }}"
                         data-cookie-id-table="activityReport"
                         data-pagination="true"
                         data-id-table="activityReport"
@@ -43,56 +44,6 @@ class="table table-striped snipe-table"
                         "fileName": "activity-report-{{ date('Y-m-d') }}",
                         "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
                         }'>
-
-                    <thead>
-                        <tr>
-                            <th data-field="id" class="hidden-xs "data-sortable="true" data-visible="false">
-                                {{ trans('general.id') }}
-                            </th>
-                            <th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">
-                                {{ trans('admin/hardware/table.icon') }}
-                            </th>
-                            <th class="col-sm-3" data-searchable="false" data-sortable="true" data-field="created_at" data-formatter="dateDisplayFormatter">
-                                {{ trans('general.date') }}
-                            </th>
-                            <th class="col-sm-2" data-searchable="true" data-sortable="true" data-field="created_by" data-formatter="usersLinkObjFormatter">
-                                {{ trans('general.admin') }}
-                            </th>
-                            <th class="col-sm-2" data-field="action_type">
-                                {{ trans('general.action') }}
-                            </th>
-                            <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">
-                                {{ trans('general.file_name') }}
-                            </th>
-                            <th class="col-sm-1" data-field="item_type" data-searchable="true" data-formatter="itemTypeFormatter">
-                                {{ trans('general.type') }}
-                            </th>
-                            <th class="col-sm-3" data-field="item.serial" data-visible="false">
-                                {{ trans('admin/hardware/table.serial') }}
-                            </th>
-                            <th class="col-sm-3" data-field="item" data-formatter="polymorphicItemFormatter">
-                                {{ trans('general.item') }}
-                            </th>
-                            <th class="col-sm-2" data-field="target" data-formatter="polymorphicItemFormatter">
-                                {{ trans('general.to') }}
-                            </th>
-                            <th class="col-sm-1" data-field="note" data-sortable="true">
-                                {{ trans('general.notes') }}
-                            </th>
-                            <th class="col-sm-2" data-field="log_meta" data-visible="false" data-formatter="changeLogFormatter">
-                                {{ trans('general.changed') }}
-                            </th>
-                            <th data-field="remote_ip" data-visible="false" data-sortable="true">
-                                {{ trans('admin/settings/general.login_ip') }}
-                            </th>
-                            <th data-field="user_agent" data-visible="false" data-sortable="true">
-                                {{ trans('admin/settings/general.login_user_agent') }}
-                            </th>
-                            <th data-field="action_source" data-visible="false" data-sortable="true">
-                                {{ trans('general.action_source') }}
-                            </th>
-                        </tr>
-                    </thead>
                 </table>
             </div>
         </div>

From 220537fbfb8ef14dfe70aee42c3ef0ee76e56d19 Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 12:59:57 +0000
Subject: [PATCH 12/13] Updated presenter name

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/views/accessories/view.blade.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/resources/views/accessories/view.blade.php b/resources/views/accessories/view.blade.php
index c7f3ddc7a1dc..9119f6ddfa88 100644
--- a/resources/views/accessories/view.blade.php
+++ b/resources/views/accessories/view.blade.php
@@ -106,7 +106,7 @@ class="table table-striped snipe-table"
                              <div class="row">
                                  <div class="col-md-12">
                                 <table
-                                        data-columns="{{ \App\Presenters\HistoryPresenter::assignedDataTableLayout() }}"
+                                        data-columns="{{ \App\Presenters\HistoryPresenter::dataTableLayout() }}"
                                         class="table table-striped snipe-table"
                                         data-cookie-id-table="AccessoryHistoryTable"
                                         data-id-table="AccessoryHistoryTable"

From 0b48fd146513a5063ae917da385006433a177d1a Mon Sep 17 00:00:00 2001
From: snipe <snipe@snipe.net>
Date: Mon, 10 Mar 2025 13:05:31 +0000
Subject: [PATCH 13/13] Removed extra headers

Signed-off-by: snipe <snipe@snipe.net>
---
 resources/views/accessories/view.blade.php | 33 +---------------------
 1 file changed, 1 insertion(+), 32 deletions(-)

diff --git a/resources/views/accessories/view.blade.php b/resources/views/accessories/view.blade.php
index 9119f6ddfa88..fc86bbd3c0a1 100644
--- a/resources/views/accessories/view.blade.php
+++ b/resources/views/accessories/view.blade.php
@@ -121,38 +121,7 @@ class="table table-striped snipe-table"
                        "fileName": "export-{{ str_slug($accessory->name) }}-history-{{ date('Y-m-d') }}",
                        "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
                      }'
-                                                data-url="{{ route('api.activity.index', ['item_id' => $accessory->id, 'item_type' => 'accessory']) }}">
-
-                                            <thead>
-                                            <tr>
-                                                <th class="col-sm-2" data-visible="false" data-sortable="true" data-field="created_at" data-formatter="dateDisplayFormatter">
-                                                    {{ trans('general.date') }}
-                                                </th>
-                                                <th class="col-sm-2" data-visible="true" data-sortable="true" data-field="admin" data-formatter="usersLinkObjFormatter">
-                                                    {{ trans('general.admin_user') }}
-                                                </th>
-                                                <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="action_type">
-                                                    {{ trans('general.action') }}
-                                                </th>
-                                                <th class="col-sm-2" data-field="file" data-visible="false" data-formatter="fileUploadNameFormatter">
-                                                    {{ trans('general.file_name') }}
-                                                </th>
-                                                <th class="col-sm-2" data-sortable="true"  data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">
-                                                    {{ trans('general.item') }}
-                                                </th>
-                                                <th class="col-sm-2" data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">
-                                                    {{ trans('general.target') }}
-                                                </th>
-                                                <th class="col-sm-2" data-sortable="true" data-visible="true" data-field="note">
-                                                    {{ trans('general.notes') }}
-                                                </th>
-                                                @if  ($snipeSettings->require_accept_signature=='1')
-                                                    <th class="col-md-3" data-field="signature_file" data-visible="false"  data-formatter="imageFormatter">
-                                                        {{ trans('general.signature') }}
-                                                    </th>
-                                                @endif
-                                            </tr>
-                                            </thead>
+                                        data-url="{{ route('api.activity.index', ['item_id' => $accessory->id, 'item_type' => 'accessory']) }}">
                                         </table>
                                     </div> <!-- /.col-md-12-->
                                 </div> <!-- /.row-->