From 3daa6dd0518caa744dcc1c569cc33e79cd014e9c Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:13:28 +0100 Subject: [PATCH 01/35] Added accessors for termination date --- app/Models/License.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Models/License.php b/app/Models/License.php index 8630080d14..cf59ac9aec 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -8,6 +8,7 @@ use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\DB; From dfd05e8b5b8919122007d204d107bf7876a66857 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:13:58 +0100 Subject: [PATCH 02/35] Refactored scope --- app/Models/License.php | 103 ++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/app/Models/License.php b/app/Models/License.php index cf59ac9aec..09bc0b3038 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -157,6 +157,21 @@ class License extends Depreciable ); } + + protected function terminatesFormattedDate(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Helper::getFormattedDateObject($attributes['termination_date'], 'date', false) : null, + ); + } + + protected function terminatesDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Carbon::parse($attributes['termination_date'])->diffForHumans() : null, + ); + } + public function prepareLimitChangeRule($parameters, $field) { $actual_seat_count = $this->licenseseats()->count(); //we use the *actual* seat count here, in case your license has gone wonky @@ -707,49 +722,6 @@ class License extends Depreciable return $this->hasMany(\App\Models\LicenseSeat::class)->whereNull('assigned_to')->whereNull('deleted_at')->whereNull('asset_id'); } - /** - * Returns expiring licenses. - * - * This checks if: - * - * 1) The license has not been deleted - * 2) The expiration date is between now and the number of days specified - * 3) There is an expiration date set and the termination date has not passed - * 4) The license termination date is null or has not passed - * - * @author A. Gianotto - * @since [v1.0] - * @return \Illuminate\Database\Eloquent\Relations\Relation - * @see \App\Console\Commands\SendExpiringLicenseNotifications - */ - public static function getExpiringLicenses($days = 60) - { - - return self::whereNull('licenses.deleted_at') - - // The termination date is null or within range - ->where(function ($query) use ($days) { - $query->whereNull('termination_date') - ->orWhereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); - }) - ->where(function ($query) use ($days) { - $query->whereNotNull('expiration_date') - // Handle expired licenses without termination dates - ->where(function ($query) use ($days) { - $query->whereNull('termination_date') - ->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]); - }) - - // Handle expired licenses with termination dates in the future - ->orWhere(function ($query) use ($days) { - $query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); - }); - }) - ->orderBy('expiration_date', 'ASC') - ->orderBy('termination_date', 'ASC') - ->get(); - } - public function scopeActiveLicenses($query) { @@ -766,20 +738,43 @@ class License extends Depreciable }); } - public function scopeExpiredLicenses($query) + /** + * Expiring/terminating licenses scope + * + * This checks if: + * + * 1) The license has not been deleted + * 2) The expiration date is between now and the number of days specified + * 3) There is an expiration date set and the termination date has not passed + * 4) The license termination date is null or has not passed + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + * @see \App\Console\Commands\SendExpiringLicenseNotifications + */ + public function scopeExpiredLicenses($query, $days = 60) { + return $query// The termination date is null or within range + ->where(function ($query) use ($days) { + $query->whereNull('termination_date') + ->orWhereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); + }) + ->where(function ($query) use ($days) { + $query->whereNotNull('expiration_date') + // Handle expired licenses without termination dates + ->where(function ($query) use ($days) { + $query->whereNull('termination_date') + ->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]); + }) - return $query->whereNull('licenses.deleted_at') - - // The termination date is null or within range - ->where(function ($query) { - $query->whereNull('termination_date') - ->orWhereDate('termination_date', '<=', [Carbon::now()]); + // Handle expired licenses with termination dates in the future + ->orWhere(function ($query) use ($days) { + $query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); + }); }) - ->orWhere(function ($query) { - $query->whereNull('expiration_date') - ->orWhereDate('expiration_date', '<=', [Carbon::now()]); - }); + ->orderBy('expiration_date', 'ASC') + ->orderBy('termination_date', 'ASC'); } /** From 8918b17f7770cb8554602ce4a5352e37a825bc1e Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:36:16 +0100 Subject: [PATCH 03/35] Updated test --- tests/Unit/SnipeModelTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/Unit/SnipeModelTest.php b/tests/Unit/SnipeModelTest.php index d36b6e4289..bfc81a5670 100644 --- a/tests/Unit/SnipeModelTest.php +++ b/tests/Unit/SnipeModelTest.php @@ -10,9 +10,12 @@ class SnipeModelTest extends TestCase { $c = new SnipeModel; $c->purchase_date = ''; - $this->assertTrue($c->purchase_date === null); - $c->purchase_date = '2016-03-25 12:35:50'; - $this->assertTrue($c->purchase_date === '2016-03-25 12:35:50'); + $this->assertNull($c->purchase_date); + $c->purchase_date = null; + $this->assertNull($c->purchase_date); + $c->purchase_date = '2016-03-25'; + $this->assertTrue($c->purchase_date === '2016-03-25'); + $this->assertEquals('2016-03-25', $c->purchase_date); } public function testSetsPurchaseCostsAppropriately() From ae43f93d0aa9b6249f823e5a4f3bcf3d87b8c408 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:37:12 +0100 Subject: [PATCH 04/35] Improved expiring assets and licenses email --- .../markdown/report-expiring-assets.blade.php | 38 ++++++------------- .../report-expiring-licenses.blade.php | 18 ++++----- 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/resources/views/notifications/markdown/report-expiring-assets.blade.php b/resources/views/notifications/markdown/report-expiring-assets.blade.php index 7fad77e022..be961ec620 100644 --- a/resources/views/notifications/markdown/report-expiring-assets.blade.php +++ b/resources/views/notifications/markdown/report-expiring-assets.blade.php @@ -1,38 +1,22 @@ @component('mail::message') {{ trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count'=>$assets->count(), 'threshold' => $threshold]) }} - - | | | | | ------------- | ------------- | ------------- | @foreach ($assets as $asset) -@php - $warranty_expires = \App\Helpers\Helper::getFormattedDateObject($asset->present()->warranty_expires, 'date'); - $eol_date = \App\Helpers\Helper::getFormattedDateObject($asset->asset_eol_date, 'date'); - $warranty_diff = ($asset->present()->warranty_expires) ? round(\Carbon\Carbon::now()->diffInDays(\Carbon\Carbon::parse($warranty_expires['date']), false), 1) : ''; - $eol_diff = round(\Carbon\Carbon::now()->diffInDays(\Carbon\Carbon::parse($asset->asset_eol_date), false), 1); - $icon = ($warranty_diff <= $threshold && $warranty_diff >= 0) ? 'âš ī¸' : (($eol_diff <= $threshold && $eol_diff >= 0) ? '🚨' : 'â„šī¸'); -@endphp -| {{ $icon }} **{{ trans('mail.name') }}** | {{ $asset->display_name }}
{{trans('mail.serial').': '.$asset->serial}} | -@if ($warranty_expires) -| **{{ trans('mail.expires') }}** | {{ !is_null($warranty_expires) ? $warranty_expires['formatted'] : '' }} ({{ $warranty_diff }} {{ trans('mail.Days') }}) | +| {{ ($asset->eol_diff_for_humans <= ($threshold / 2)) ? '🚨' : (($asset->eol_diff_for_humans <= $threshold) ? 'âš ī¸' : ' ') }} **{{ trans('mail.name') }}** | {{ $asset->display_name }} | +@if ($asset->serial) +| **{{ trans('general.serial_number') }}** | {{ $asset->serial }} | @endif -@if ($eol_date) -| **{{ trans('mail.eol') }}** | {{ !is_null($eol_date) ? $eol_date['formatted'] : '' }} ({{ $eol_diff }} {{ trans('mail.Days') }}) | +@if ($asset->purchase_date) +| **{{ trans('general.purchase_date') }}** | {{ $asset->purchase_date_formatted }} | +@endif +@if ($asset->warranty_expires) +| **{{ trans('mail.expires') }}** | {{ $asset->warranty_expires_formatted_date }} ({{ $asset->warranty_expires_diff_for_humans }}) | +@endif +@if ($asset->eol_date && $asset->eol_diff_for_humans) +| **{{ trans('mail.eol') }}** | {{ $asset->eol_formatted_date }} ({{ $asset->eol_diff_for_humans }}) | @endif @if ($asset->supplier) | **{{ trans('mail.supplier') }}** | {{ ($asset->supplier ? e($asset->supplier->name) : '') }} | diff --git a/resources/views/notifications/markdown/report-expiring-licenses.blade.php b/resources/views/notifications/markdown/report-expiring-licenses.blade.php index d7a68cfb32..e165e74433 100644 --- a/resources/views/notifications/markdown/report-expiring-licenses.blade.php +++ b/resources/views/notifications/markdown/report-expiring-licenses.blade.php @@ -1,17 +1,13 @@ @component('mail::message') {{ trans_choice('mail.license_expiring_alert', $licenses->count(), ['count'=>$licenses->count(), 'threshold' => $threshold]) }} -@component('mail::table') - - + + +| | {{ trans('mail.name') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | +| :------------- | :------------- | :------------- | :------------- | @foreach ($licenses as $license) -@php -$expires = Helper::getFormattedDateObject($license->expiration_date, 'date'); -$diff = round(abs(strtotime($license->expiration_date->format('Y-m-d')) - strtotime(date('Y-m-d')))/86400); -$icon = ($diff <= ($threshold / 2)) ? '🚨' : (($diff <= $threshold) ? 'âš ī¸' : ' '); -@endphp - +| {{ ($license->expires_diff_for_humans <= ($threshold / 2)) ? '🚨' : (($license->expires_diff_for_humans <= $threshold) ? 'âš ī¸' : ' ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {!! $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' !!} | +|
|
|
|
| @endforeach -
 {{ trans('mail.name') }}{{ trans('mail.Days') }}{{ trans('mail.expires') }}
{{ $icon }} {{ $license->name }} {{ $diff }} {{ trans('mail.Days') }} {{ $expires['formatted'] }}
+
@endcomponent -@endcomponent \ No newline at end of file From c36125dc95aadb5f28c6d159b495d42cbc002369 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:37:25 +0100 Subject: [PATCH 05/35] Added CSS to the message blade --- resources/views/vendor/mail/html/message.blade.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/resources/views/vendor/mail/html/message.blade.php b/resources/views/vendor/mail/html/message.blade.php index e958eca627..04489cd8ac 100644 --- a/resources/views/vendor/mail/html/message.blade.php +++ b/resources/views/vendor/mail/html/message.blade.php @@ -3,7 +3,20 @@ @slot('header') {{-- Check that the $snipeSettings variable is set, images are set to be shown, and setup is complete --}} + @if (isset($snipeSettings) && ($snipeSettings::setupCompleted())) From dd06a530c0b40e8e2ad1f46e6b57aa02e6f2bbc4 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:37:43 +0100 Subject: [PATCH 06/35] Added Terminates string --- resources/lang/en-US/mail.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/en-US/mail.php b/resources/lang/en-US/mail.php index 707390e4f0..70ee6ba42f 100644 --- a/resources/lang/en-US/mail.php +++ b/resources/lang/en-US/mail.php @@ -59,6 +59,7 @@ return [ 'days' => 'Days', 'expecting_checkin_date' => 'Expected Checkin Date', 'expires' => 'Expires', + 'terminates' => 'Terminates', 'following_accepted' => 'The following was accepted', 'following_declined' => 'The following was declined', 'hello' => 'Hello', From 4702fdddc6bf72c5a0597da6372343c972497d79 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:38:08 +0100 Subject: [PATCH 07/35] Nicer output in console command --- app/Console/Commands/SendExpirationAlerts.php | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/app/Console/Commands/SendExpirationAlerts.php b/app/Console/Commands/SendExpirationAlerts.php index cfe563e404..b8e16e57e6 100644 --- a/app/Console/Commands/SendExpirationAlerts.php +++ b/app/Console/Commands/SendExpirationAlerts.php @@ -60,19 +60,51 @@ class SendExpirationAlerts extends Command Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval)); $this->table( - ['ID', 'Tag', 'Model', 'Model Number', 'EOL', 'EOL Months', 'Warranty Expires', 'Warranty Months'], - $assets->map(fn($item) => ['ID' => $item->id, 'Tag' => $item->asset_tag, 'Model' => $item->model->name, 'Model Number' => $item->model->model_number, 'EOL' => $item->asset_eol_date, 'EOL Months' => $item->model->eol, 'Warranty Expires' => $item->warranty_expires, 'Warranty Months' => $item->warranty_months]) - ); + [ + trans('general.id'), + trans('admin/hardware/form.tag'), + trans('admin/hardware/form.model'), + trans('general.model_no'), + trans('general.purchase_date'), + trans('admin/hardware/form.eol_rate'), + trans('admin/hardware/form.eol_date'), + trans('admin/hardware/form.warranty_expires'), + ], + $assets->map(fn($item) => + [ + trans('general.id') => $item->id, + trans('admin/hardware/form.tag') => $item->asset_tag, + trans('admin/hardware/form.model') => $item->model->name, + trans('general.model_no') => $item->model->model_number, + trans('general.purchase_date') => $item->purchase_date_formatted_date, + trans('admin/hardware/form.eol_rate') => $item->model->eol, + trans('admin/hardware/form.eol_date') => $item->eol_date ? $item->eol_formatted_date .' ('.$item->eol_diff_for_humans.')' : '', + trans('admin/hardware/form.warranty_expires') => $item->warranty_expires ? $item->warranty_expires_formatted_date .' ('.$item->warranty_expires_diff_for_humans.')' : '', + ]) + ); } // Expiring licenses - $licenses = License::getExpiringLicenses($alert_interval); + $licenses = License::query()->ExpiredLicenses($alert_interval)->get(); if ($licenses->count() > 0) { Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval)); $this->table( - ['ID', 'Name', 'Expires', 'Termination Date'], - $licenses->map(fn($item) => ['ID' => $item->id, 'Name' => $item->name, 'Expires' => $item->expiration_date, 'Termination Date' => $item->termination_date]) + [ + trans('general.id'), + trans('general.name'), + trans('admin/licenses/form.expiration'), + trans('mail.expires'), + trans('admin/licenses/form.termination_date'), + trans('mail.terminates')], + $licenses->map(fn($item) => [ + trans('general.id') => $item->id, + trans('general.name') => $item->name, + trans('admin/licenses/form.expiration') => $item->expires_formatted_date, + trans('mail.expires') => $item->expires_diff_for_humans, + trans('admin/licenses/form.termination_date') => $item->terminates_formatted_date, + trans('mail.terminates') => $item->terminates_diff_for_humans + ]) ); } From d7bf9b7f2eb31dbb50bb5eda31949da38817d575 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:38:37 +0100 Subject: [PATCH 08/35] Added more accessors and mutators --- app/Models/Asset.php | 81 +++++++++++++++++++++++++++++++++------ app/Models/SnipeModel.php | 43 ++++++++++++++++++--- 2 files changed, 107 insertions(+), 17 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index e6eb590a48..f21454698a 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -227,7 +227,6 @@ class Asset extends Depreciable } - public function customFieldValidationRules() { @@ -266,7 +265,6 @@ class Asset extends Depreciable return parent::save($params); } - public function getDisplayNameAttribute() { return $this->present()->name(); @@ -277,20 +275,79 @@ class Asset extends Depreciable * * @return \Carbon\Carbon|null */ - public function getWarrantyExpiresAttribute() + + + protected function warrantyExpires(): Attribute { - if (isset($this->attributes['warranty_months']) && isset($this->attributes['purchase_date'])) { - if (is_string($this->attributes['purchase_date']) || is_string($this->attributes['purchase_date'])) { - $purchase_date = \Carbon\Carbon::parse($this->attributes['purchase_date']); - } else { - $purchase_date = \Carbon\Carbon::instance($this->attributes['purchase_date']); + return Attribute:: make( + get: fn(mixed $value, array $attributes) => ($attributes['warranty_months'] && $attributes['purchase_date']) ? Carbon::parse($attributes['purchase_date'])->addMonths($attributes['warranty_months']) : null, + ); + } + + protected function warrantyExpiresFormattedDate(): Attribute + { + + return Attribute:: make( + get: fn(mixed $value, array $attributes) => Helper::getFormattedDateObject($this->warrantyExpires, 'date', false) + ); + } + + protected function warrantyExpiresDiff(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->warrantyExpires ? round((Carbon::now()->diffInDays($this->warrantyExpires))) : null, + ); + + } + + protected function warrantyExpiresDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->warrantyExpires ? Carbon::parse($this->warrantyExpires)->diffForHumans() : null, + ); + + } + + protected function eolDate(): Attribute + { + + return Attribute:: make( + get: function(mixed $value, array $attributes) { + if ($attributes['asset_eol_date'] && $attributes['eol_explicit'] == '1') { + return Carbon::parse($attributes['asset_eol_date']); + } elseif ($attributes['purchase_date'] && $this->model && ((int) $this->model->eol > 0)) { + return Carbon::parse($attributes['purchase_date'])->addMonths((int) $this->model->eol); + } else { + return null; + } } - $purchase_date->setTime(0, 0, 0); + ); - return $purchase_date->addMonths((int) $this->attributes['warranty_months']); - } + } + + + protected function eolFormattedDate(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->eolDate ? Helper::getFormattedDateObject($this->eolDate, 'date', false) : null, + ); + } + + protected function eolDiff(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->eolDate ? round((Carbon::now()->diffInDays(Carbon::parse($this->eolDate), false, 1))) : null, + ); + + } + + protected function eolDiffForHumans(): Attribute + { + + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->eolDate ? Carbon::parse($this->eolDate)->diffForHumans() : null, + ); - return null; } diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index ae65664474..b4db5f2c95 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Helpers\Helper; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; @@ -11,12 +12,43 @@ use Illuminate\Support\Facades\Request; class SnipeModel extends Model { // Setters that are appropriate across multiple models. - public function setPurchaseDateAttribute($value) + + + protected function purchaseDate(): Attribute { - if ($value == '') { - $value = null; - } - $this->attributes['purchase_date'] = $value; + return Attribute:: make( + set: fn(mixed $value) => $value ?: null, + get: fn(mixed $value) => $value, + ); + } + + protected function purchaseDateFormatted(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['purchase_date'] ? Helper::getFormattedDateObject(Carbon::parse($attributes['purchase_date']), 'date', false) : null, + ); + } + + + protected function expiresDiff(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? round((Carbon::now()->diffInDays(Carbon::parse($attributes['expiration_date']), false, 1))) : null, + ); + } + + protected function expiresDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? Carbon::parse($attributes['expiration_date'])->diffForHumans() : null, + ); + } + + protected function expiresFormattedDate(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? Helper::getFormattedDateObject($attributes['expiration_date'], 'date', false) : null, + ); } /** @@ -180,6 +212,7 @@ class SnipeModel extends Model ); } + public function getEula() { From 013c50607aafafb7d0f4e5db2dd7d3d166c3e69d Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 14:46:32 +0100 Subject: [PATCH 09/35] Put old setter back because reasons? --- app/Models/SnipeModel.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index b4db5f2c95..b9a1f1c171 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -12,16 +12,15 @@ use Illuminate\Support\Facades\Request; class SnipeModel extends Model { // Setters that are appropriate across multiple models. - - - protected function purchaseDate(): Attribute + public function setPurchaseDateAttribute($value) { - return Attribute:: make( - set: fn(mixed $value) => $value ?: null, - get: fn(mixed $value) => $value, - ); + if ($value == '') { + $value = null; + } + $this->attributes['purchase_date'] = $value; } + protected function purchaseDateFormatted(): Attribute { return Attribute:: make( From 1cd9fc47aae1491df7d1972966ae3ef4b99febe5 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 15:03:14 +0100 Subject: [PATCH 10/35] Use diff_in_days instead --- app/Models/Asset.php | 2 +- app/Models/License.php | 8 ++++++++ app/Models/SnipeModel.php | 5 +++-- .../markdown/report-expiring-assets.blade.php | 2 +- .../markdown/report-expiring-licenses.blade.php | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index f21454698a..de88662836 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -333,7 +333,7 @@ class Asset extends Depreciable ); } - protected function eolDiff(): Attribute + protected function eolDiffInDays(): Attribute { return Attribute:: make( get: fn(mixed $value, array $attributes) => $this->eolDate ? round((Carbon::now()->diffInDays(Carbon::parse($this->eolDate), false, 1))) : null, diff --git a/app/Models/License.php b/app/Models/License.php index 09bc0b3038..73d7c22c3d 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -165,6 +165,13 @@ class License extends Depreciable ); } + protected function terminatesDiffInDays(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Carbon::parse($attributes['termination_date'])->diffInDays() : null, + ); + } + protected function terminatesDiffForHumans(): Attribute { return Attribute:: make( @@ -172,6 +179,7 @@ class License extends Depreciable ); } + public function prepareLimitChangeRule($parameters, $field) { $actual_seat_count = $this->licenseseats()->count(); //we use the *actual* seat count here, in case your license has gone wonky diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index b9a1f1c171..37f513bf9d 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -29,13 +29,14 @@ class SnipeModel extends Model } - protected function expiresDiff(): Attribute + protected function expiresDiffInDays(): Attribute { return Attribute:: make( - get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? round((Carbon::now()->diffInDays(Carbon::parse($attributes['expiration_date']), false, 1))) : null, + get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? Carbon::parse($attributes['expiration_date'])->diffInDays() : null, ); } + protected function expiresDiffForHumans(): Attribute { return Attribute:: make( diff --git a/resources/views/notifications/markdown/report-expiring-assets.blade.php b/resources/views/notifications/markdown/report-expiring-assets.blade.php index be961ec620..1b35b7a309 100644 --- a/resources/views/notifications/markdown/report-expiring-assets.blade.php +++ b/resources/views/notifications/markdown/report-expiring-assets.blade.php @@ -5,7 +5,7 @@ | | | | | ------------- | ------------- | ------------- | @foreach ($assets as $asset) -| {{ ($asset->eol_diff_for_humans <= ($threshold / 2)) ? '🚨' : (($asset->eol_diff_for_humans <= $threshold) ? 'âš ī¸' : ' ') }} **{{ trans('mail.name') }}** | {{ $asset->display_name }} | +| {{ ($asset->eol_diff_in_days <= ($threshold / 2)) ? '🚨' : (($asset->eol_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} **{{ trans('mail.name') }}** | {{ $asset->display_name }} | @if ($asset->serial) | **{{ trans('general.serial_number') }}** | {{ $asset->serial }} | @endif diff --git a/resources/views/notifications/markdown/report-expiring-licenses.blade.php b/resources/views/notifications/markdown/report-expiring-licenses.blade.php index e165e74433..e5445cd50e 100644 --- a/resources/views/notifications/markdown/report-expiring-licenses.blade.php +++ b/resources/views/notifications/markdown/report-expiring-licenses.blade.php @@ -6,7 +6,7 @@ | | {{ trans('mail.name') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | | :------------- | :------------- | :------------- | :------------- | @foreach ($licenses as $license) -| {{ ($license->expires_diff_for_humans <= ($threshold / 2)) ? '🚨' : (($license->expires_diff_for_humans <= $threshold) ? 'âš ī¸' : ' ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {!! $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' !!} | +| {{ (($license->isExpired()) || ($license->isTerminated())) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {!! $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' !!} | |
|
|
|
| @endforeach From ae7ccbb7bda2924de5ffa3f7c2b0efa5eba716b3 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 15:59:55 +0100 Subject: [PATCH 11/35] Fixed icons --- .../notifications/markdown/report-expiring-licenses.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/notifications/markdown/report-expiring-licenses.blade.php b/resources/views/notifications/markdown/report-expiring-licenses.blade.php index e5445cd50e..d1d89040c9 100644 --- a/resources/views/notifications/markdown/report-expiring-licenses.blade.php +++ b/resources/views/notifications/markdown/report-expiring-licenses.blade.php @@ -6,7 +6,7 @@ | | {{ trans('mail.name') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | | :------------- | :------------- | :------------- | :------------- | @foreach ($licenses as $license) -| {{ (($license->isExpired()) || ($license->isTerminated())) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {!! $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' !!} | +| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {!! $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' !!}| |
|
|
|
| @endforeach From 5ceb50d7e5f2d6a50f3ba96f6b84c7274d230ddb Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:00:23 +0100 Subject: [PATCH 12/35] Added expiring licenses to API and UI --- .../Controllers/Api/LicensesController.php | 4 +++ .../views/partials/bootstrap-table.blade.php | 34 +++++++------------ 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index 105a20bd86..738311b52b 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -7,6 +7,7 @@ use App\Http\Controllers\Controller; use App\Http\Transformers\LicensesTransformer; use App\Http\Transformers\SelectlistTransformer; use App\Models\License; +use App\Models\Setting; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Http\JsonResponse; @@ -25,9 +26,12 @@ class LicensesController extends Controller $this->authorize('view', License::class); $licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count'); + $settings = Setting::getSettings(); if ($request->input('status')=='inactive') { $licenses->ExpiredLicenses(); + } elseif ($request->input('status')=='expiring') { + $licenses->ExpiringLicenses($settings->alert_interval); } else { $licenses->ActiveLicenses(); } diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 8ebbc9fb16..9e74b3cf69 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -1605,26 +1605,6 @@ }); @endcan - @can('create', \App\Models\Component::class) - // License table buttons - window.licenseButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('licenses.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - @can('create', \App\Models\Department::class) // Department table buttons window.departmentButtons = () => ({ @@ -1787,9 +1767,21 @@ } }, + btnShowExpiring: { + text: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', + icon: 'fas fa-clock {{ (request()->input('status') == "expiring") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('status') == "expiring") ? route('licenses.index') : route('licenses.index', ['status' => 'expiring']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', + + } + }, + btnShowInactive: { text: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', - icon: 'fas fa-clock {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}', + icon: 'fas fa-history {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}', event () { window.location.href = '{{ (request()->input('status') == "inactive") ? route('licenses.index') : route('licenses.index', ['status' => 'inactive']) }}'; }, From 4934dc85accc1e32b178d450c81a5e53c5a5b44b Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:00:58 +0100 Subject: [PATCH 13/35] Reverse expires diff direction --- app/Models/License.php | 29 ++++++++++++++++++++++------- app/Models/SnipeModel.php | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/app/Models/License.php b/app/Models/License.php index 73d7c22c3d..897107dee9 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -168,7 +168,7 @@ class License extends Depreciable protected function terminatesDiffInDays(): Attribute { return Attribute:: make( - get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Carbon::parse($attributes['termination_date'])->diffInDays() : null, + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Carbon::now()->diffInDays($attributes['termination_date']) : null, ); } @@ -746,6 +746,23 @@ class License extends Depreciable }); } + /** + * Expiried/terminated licenses scope + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + * @see \App\Console\Commands\SendExpiringLicenseNotifications + */ + public function scopeExpiredLicenses($query) + { + return $query->whereDate('termination_date', '<=', Carbon::now())// The termination date is null or within range + ->orWhere(function ($query) { + $query->whereDate('expiration_date', '<=', Carbon::now()); + }) + ->whereNull('deleted_at'); + } + /** * Expiring/terminating licenses scope * @@ -761,7 +778,7 @@ class License extends Depreciable * @return \Illuminate\Database\Eloquent\Relations\Relation * @see \App\Console\Commands\SendExpiringLicenseNotifications */ - public function scopeExpiredLicenses($query, $days = 60) + public function scopeExpiringLicenses($query, $days = 60) { return $query// The termination date is null or within range ->where(function ($query) use ($days) { @@ -770,19 +787,17 @@ class License extends Depreciable }) ->where(function ($query) use ($days) { $query->whereNotNull('expiration_date') - // Handle expired licenses without termination dates + // Handle expiring licenses without termination dates ->where(function ($query) use ($days) { $query->whereNull('termination_date') ->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]); }) - // Handle expired licenses with termination dates in the future + // Handle expiring licenses with termination dates in the future ->orWhere(function ($query) use ($days) { $query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); }); - }) - ->orderBy('expiration_date', 'ASC') - ->orderBy('termination_date', 'ASC'); + }); } /** diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index 37f513bf9d..c4a72d35d7 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -32,7 +32,7 @@ class SnipeModel extends Model protected function expiresDiffInDays(): Attribute { return Attribute:: make( - get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? Carbon::parse($attributes['expiration_date'])->diffInDays() : null, + get: fn(mixed $value, array $attributes) => $attributes['expiration_date'] ? Carbon::now()->diffInDays($attributes['expiration_date']) : null, ); } From 35bf0d020e0a94e1e0af54db9327ade9d922e9a1 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:01:27 +0100 Subject: [PATCH 14/35] Added breadcrumb to expiring --- app/Providers/BreadcrumbsServiceProvider.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Providers/BreadcrumbsServiceProvider.php b/app/Providers/BreadcrumbsServiceProvider.php index 07c912bfb7..23fb88a96f 100644 --- a/app/Providers/BreadcrumbsServiceProvider.php +++ b/app/Providers/BreadcrumbsServiceProvider.php @@ -350,10 +350,15 @@ class BreadcrumbsServiceProvider extends ServiceProvider * Licenses Breadcrumbs */ if ((request()->is('licenses*')) && (request()->status=='inactive')) { + Breadcrumbs::for('licenses.index', fn(Trail $trail) => $trail->parent('home', route('home')) + ->push(trans('general.licenses'), route('licenses.index')) + ->push(trans('general.show_inactive'), route('licenses.index')) + ); + } elseif ((request()->is('licenses*')) && (request()->status=='expiring')) { Breadcrumbs::for('licenses.index', fn (Trail $trail) => $trail->parent('home', route('home')) ->push(trans('general.licenses'), route('licenses.index')) - ->push(trans('general.show_inactive'), route('licenses.index')) + ->push(trans('general.show_expiring'), route('licenses.index')) ); } else { Breadcrumbs::for('licenses.index', fn (Trail $trail) => From 4934e7666c332a68d67450456e77b753aa66f958 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:01:38 +0100 Subject: [PATCH 15/35] Added text string --- resources/lang/en-US/general.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/en-US/general.php b/resources/lang/en-US/general.php index 630442c90f..c59a2ebeb4 100644 --- a/resources/lang/en-US/general.php +++ b/resources/lang/en-US/general.php @@ -595,6 +595,7 @@ return [ ], 'show_inactive' => 'Expired or Terminated', + 'show_expiring' => 'Expiring or Terminating Soon', 'more_info' => 'More Info', 'quickscan_bulk_help' => 'Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log. Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to.', 'whoops' => 'Whoops!', From 44d31d4b39b687109cabbbbbd4e8ae14b9ac3c72 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:01:49 +0100 Subject: [PATCH 16/35] Moved date fields closer together --- app/Presenters/LicensePresenter.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php index a1edf2cf76..ea5c3b5d73 100644 --- a/app/Presenters/LicensePresenter.php +++ b/app/Presenters/LicensePresenter.php @@ -48,6 +48,13 @@ class LicensePresenter extends Presenter 'sortable' => true, 'title' => trans('admin/licenses/form.expiration'), 'formatter' => 'dateDisplayFormatter', + ], [ + 'field' => 'termination_date', + 'searchable' => true, + 'sortable' => true, + 'visible' => false, + 'title' => trans('admin/licenses/form.termination_date'), + 'formatter' => 'dateDisplayFormatter', ], [ 'field' => 'license_email', 'searchable' => true, @@ -110,14 +117,6 @@ class LicensePresenter extends Presenter 'title' => trans('general.purchase_date'), 'formatter' => 'dateDisplayFormatter', ], - [ - 'field' => 'termination_date', - 'searchable' => true, - 'sortable' => true, - 'visible' => false, - 'title' => trans('admin/licenses/form.termination_date'), - 'formatter' => 'dateDisplayFormatter', - ], [ 'field' => 'depreciation', 'searchable' => true, From ec2eddf538210240b96cad6653a4e0cce610d5a7 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:02:07 +0100 Subject: [PATCH 17/35] Add order scope to query --- app/Console/Commands/SendExpirationAlerts.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Console/Commands/SendExpirationAlerts.php b/app/Console/Commands/SendExpirationAlerts.php index b8e16e57e6..44ca9dce65 100644 --- a/app/Console/Commands/SendExpirationAlerts.php +++ b/app/Console/Commands/SendExpirationAlerts.php @@ -85,7 +85,10 @@ class SendExpirationAlerts extends Command } // Expiring licenses - $licenses = License::query()->ExpiredLicenses($alert_interval)->get(); + $licenses = License::query()->ExpiringLicenses($alert_interval) + ->orderBy('expiration_date', 'ASC') + ->orderBy('termination_date', 'ASC') + ->get(); if ($licenses->count() > 0) { Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval)); From 90f4dfb48b15473d23aae8d2cd951fad5e12f4d1 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:03:03 +0100 Subject: [PATCH 18/35] Use regular blade syntax --- .../notifications/markdown/report-expiring-licenses.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/notifications/markdown/report-expiring-licenses.blade.php b/resources/views/notifications/markdown/report-expiring-licenses.blade.php index d1d89040c9..aaf1fc629d 100644 --- a/resources/views/notifications/markdown/report-expiring-licenses.blade.php +++ b/resources/views/notifications/markdown/report-expiring-licenses.blade.php @@ -6,7 +6,7 @@ | | {{ trans('mail.name') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | | :------------- | :------------- | :------------- | :------------- | @foreach ($licenses as $license) -| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {!! $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' !!}| +| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {{ $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' }}| |
|
|
|
| @endforeach From ae8289fc8c2ef98ba961be3aab3820389fb1acfe Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:12:40 +0100 Subject: [PATCH 19/35] Eager load cagory and manufacturer --- app/Console/Commands/SendExpirationAlerts.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Console/Commands/SendExpirationAlerts.php b/app/Console/Commands/SendExpirationAlerts.php index 44ca9dce65..7ca66ce012 100644 --- a/app/Console/Commands/SendExpirationAlerts.php +++ b/app/Console/Commands/SendExpirationAlerts.php @@ -86,6 +86,7 @@ class SendExpirationAlerts extends Command // Expiring licenses $licenses = License::query()->ExpiringLicenses($alert_interval) + ->with('manufacturer','category') ->orderBy('expiration_date', 'ASC') ->orderBy('termination_date', 'ASC') ->get(); From 530089895a79a67ecd3302203c71c2f33d235019 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:13:00 +0100 Subject: [PATCH 20/35] Added category and manufacturer to expiring license report --- .../markdown/report-expiring-licenses.blade.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/views/notifications/markdown/report-expiring-licenses.blade.php b/resources/views/notifications/markdown/report-expiring-licenses.blade.php index aaf1fc629d..3a65926c9b 100644 --- a/resources/views/notifications/markdown/report-expiring-licenses.blade.php +++ b/resources/views/notifications/markdown/report-expiring-licenses.blade.php @@ -3,11 +3,11 @@ -| | {{ trans('mail.name') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | -| :------------- | :------------- | :------------- | :------------- | +| | {{ trans('mail.name') }} | {{ trans('general.category') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | +| :------------- | :------------- | :------------- | :------------- | :------------- | @foreach ($licenses as $license) -| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {{ $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' }}| -|
|
|
|
| +| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} ({{ $license->manufacturer ? $license->manufacturer->name : '' }}) | {{ $license->category ? $license->category->name : '' }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {{ $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' }}| +|
|
|
|
|
| @endforeach
@endcomponent From 2a92c4899d23eed8d2b933cda18de029bd36d659 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:19:00 +0100 Subject: [PATCH 21/35] =?UTF-8?q?Don=E2=80=99t=20use=20parenthases=20unles?= =?UTF-8?q?s=20a=20manufacturer=20is=20given?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notifications/markdown/report-expiring-licenses.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/notifications/markdown/report-expiring-licenses.blade.php b/resources/views/notifications/markdown/report-expiring-licenses.blade.php index 3a65926c9b..6391b16ba0 100644 --- a/resources/views/notifications/markdown/report-expiring-licenses.blade.php +++ b/resources/views/notifications/markdown/report-expiring-licenses.blade.php @@ -6,7 +6,7 @@ | | {{ trans('mail.name') }} | {{ trans('general.category') }} | {{ trans('mail.expires') }} | {{ trans('mail.terminates') }} | | :------------- | :------------- | :------------- | :------------- | :------------- | @foreach ($licenses as $license) -| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} ({{ $license->manufacturer ? $license->manufacturer->name : '' }}) | {{ $license->category ? $license->category->name : '' }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {{ $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' }}| +| {{ (($license->isExpired()) || ($license->isTerminated()) || ($license->terminates_diff_in_days <= ($threshold / 2)) || ($license->expires_diff_in_days <= ($threshold / 2))) ? '🚨' : (($license->expires_diff_in_days <= $threshold) ? 'âš ī¸' : 'â„šī¸ ') }} | {{ $license->name }} {{ $license->manufacturer ? '('.$license->manufacturer->name.')' : '' }} | {{ $license->category ? $license->category->name : '' }} | {{ $license->expires_formatted_date }} {!! $license->expires_diff_for_humans ? ' ('.$license->expires_diff_for_humans .')' : '' !!} | {{ $license->terminates_formatted_date }} {{ $license->terminates_diff_for_humans ? ' ('.$license->terminates_diff_for_humans .')' : '' }}| |
|
|
|
|
| @endforeach From 0aebd669b272822ed4785c42804fc72279872238 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 16:25:31 +0100 Subject: [PATCH 22/35] Fixed accessor for console view --- app/Console/Commands/SendExpirationAlerts.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Console/Commands/SendExpirationAlerts.php b/app/Console/Commands/SendExpirationAlerts.php index 7ca66ce012..ae9bff48df 100644 --- a/app/Console/Commands/SendExpirationAlerts.php +++ b/app/Console/Commands/SendExpirationAlerts.php @@ -76,7 +76,7 @@ class SendExpirationAlerts extends Command trans('admin/hardware/form.tag') => $item->asset_tag, trans('admin/hardware/form.model') => $item->model->name, trans('general.model_no') => $item->model->model_number, - trans('general.purchase_date') => $item->purchase_date_formatted_date, + trans('general.purchase_date') => $item->purchase_date_formatted, trans('admin/hardware/form.eol_rate') => $item->model->eol, trans('admin/hardware/form.eol_date') => $item->eol_date ? $item->eol_formatted_date .' ('.$item->eol_diff_for_humans.')' : '', trans('admin/hardware/form.warranty_expires') => $item->warranty_expires ? $item->warranty_expires_formatted_date .' ('.$item->warranty_expires_diff_for_humans.')' : '', @@ -97,6 +97,7 @@ class SendExpirationAlerts extends Command [ trans('general.id'), trans('general.name'), + trans('general.purchase_date'), trans('admin/licenses/form.expiration'), trans('mail.expires'), trans('admin/licenses/form.termination_date'), @@ -104,6 +105,7 @@ class SendExpirationAlerts extends Command $licenses->map(fn($item) => [ trans('general.id') => $item->id, trans('general.name') => $item->name, + trans('general.purchase_date') => $item->purchase_date_formatted, trans('admin/licenses/form.expiration') => $item->expires_formatted_date, trans('mail.expires') => $item->expires_diff_for_humans, trans('admin/licenses/form.termination_date') => $item->terminates_formatted_date, From 6ae4a9aa1a3bfce52e0b265749def638cdc9f348 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 17:14:47 +0100 Subject: [PATCH 23/35] Added tooltips to custom btn methods --- .../views/partials/bootstrap-table.blade.php | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 9e74b3cf69..e796ee5080 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -124,7 +124,7 @@ print: 'fa-print', refresh: 'fas fa-sync-alt', export: 'fa-download', - clearSearch: 'fa-times' + clearSearch: 'fa-times', }, locale: '{{ app()->getLocale() }}', exportOptions: export_options, @@ -153,11 +153,13 @@ title = lookup[field]; if (title) { th.attr('data-toggle', 'tooltip'); + th.attr('data-tooltip', 'true'); th.attr('data-placement', 'top'); // th.attr('title', title) //this causes 'double-titles' which looks gross th.tooltip({container: 'body', title: title}); } - }) + }); + }, formatNoMatches: function () { return '{{ trans('table.no_matching_records') }}'; @@ -1276,6 +1278,7 @@ attributes: { title: '{{ trans('general.create') }}', class: 'btn btn-primary', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1290,7 +1293,8 @@ window.location.href = '{{ route('users.export') }}'; }, attributes: { - title: '{{ trans('general.export') }}' + title: '{{ trans('general.export') }}', + 'data-tooltip': true, } }, @@ -1302,6 +1306,7 @@ }, attributes: { title: '{{ trans('general.show_admins') }}', + 'data-tooltip': true, } }, @@ -1314,6 +1319,7 @@ }, attributes: { title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + 'data-tooltip': true, } }, @@ -1333,6 +1339,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1355,6 +1362,7 @@ attributes: { title: '{{ trans('general.create') }}', class: 'btn btn-primary', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1371,6 +1379,7 @@ }, attributes: { title: '{{ trans('button.add_maintenance') }}', + 'data-tooltip': true, } }, @endcan @@ -1383,7 +1392,8 @@ window.location.href = '{{ route('reports/custom') }}'; }, attributes: { - title: '{{ trans('admin/hardware/general.custom_export') }}' + title: '{{ trans('admin/hardware/general.custom_export') }}', + 'data-tooltip': true, } }, @@ -1395,6 +1405,7 @@ }, attributes: { title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', + 'data-tooltip': true, } }, @@ -1412,6 +1423,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1426,6 +1438,7 @@ }, attributes: { title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + 'data-tooltip': true, } }, @@ -1444,6 +1457,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1464,6 +1478,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1484,6 +1499,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1525,6 +1541,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1545,6 +1562,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1578,6 +1596,7 @@ }, attributes: { title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', + 'data-tooltip': true, } }, @@ -1597,6 +1616,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1617,6 +1637,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1637,6 +1658,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1657,6 +1679,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1677,6 +1700,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1697,6 +1721,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1710,6 +1735,7 @@ }, attributes: { title: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', + 'data-tooltip': true, } }, @@ -1728,6 +1754,7 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1749,10 +1776,11 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', + 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif - } + }, }, @endcan @@ -1763,7 +1791,8 @@ window.location.href = '{{ route('licenses.export', ['category_id' => (isset($category)) ? $category->id :'' ]) }}'; }, attributes: { - title: '{{ trans('general.export') }}' + title: '{{ trans('general.export') }}', + 'data-tooltip': true, } }, @@ -1775,6 +1804,7 @@ }, attributes: { title: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', + 'data-tooltip': true, } }, @@ -1787,6 +1817,7 @@ }, attributes: { title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', + 'data-tooltip': true, } }, From 51789ccbf388c3f2e9fdea6f147cc5e39630f1a1 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 18:54:05 +0100 Subject: [PATCH 24/35] Got tooltips to work on built-in buttons! --- .../views/partials/bootstrap-table.blade.php | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index e796ee5080..ab36dde4db 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -68,6 +68,8 @@ } }, classes: 'table table-responsive table-striped snipe-table table-no-bordered', + //buttonsPrefix: "btn", + buttonsClass: " tableButton", // reorderableColumns: true, stickyHeader: true, stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10), @@ -136,6 +138,8 @@ var lookup = {}; var lookup_initialized = false; var ths = $('th'); + var toolbar_buttons = $('.tableButton'); + ths.each(function (index, element) { th = $(element); //only populate the lookup table once; don't need to keep doing it. @@ -143,22 +147,40 @@ // th -> tr -> thead -> table var table = th.parent().parent().parent() var column_data = table.data('columns') + for (var column in column_data) { lookup[column_data[column].field] = column_data[column].titleTooltip; } + lookup_initialized = true } field = th.data('field'); // find fieldname this column refers to title = lookup[field]; + if (title) { th.attr('data-toggle', 'tooltip'); th.attr('data-tooltip', 'true'); th.attr('data-placement', 'top'); // th.attr('title', title) //this causes 'double-titles' which looks gross th.tooltip({container: 'body', title: title}); + } }); + + // Add tooltips to the toolbar buttons too + toolbar_buttons.each(function (index, element) { + tableButton = $(element); + title = tableButton.attr('title'); + + if (title) { + tableButton.attr('data-toggle', 'tooltip'); + tableButton.attr('data-tooltip', 'true'); + tableButton.attr('data-placement', 'top'); + tableButton.tooltip({container: 'body', title: title}); + } + }); + }, formatNoMatches: function () { @@ -1278,7 +1300,6 @@ attributes: { title: '{{ trans('general.create') }}', class: 'btn btn-primary', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1287,14 +1308,13 @@ @endcan btnExport: { - text: '{{ trans('general.export') }}', + text: '{{ trans('general.export_all_to_csv') }}', icon: 'fa-solid fa-file-csv', event () { window.location.href = '{{ route('users.export') }}'; }, attributes: { - title: '{{ trans('general.export') }}', - 'data-tooltip': true, + title: '{{ trans('general.export_all_to_csv') }}', } }, @@ -1306,8 +1326,6 @@ }, attributes: { title: '{{ trans('general.show_admins') }}', - 'data-tooltip': true, - } }, @@ -1319,7 +1337,6 @@ }, attributes: { title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - 'data-tooltip': true, } }, @@ -1339,7 +1356,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1362,7 +1378,6 @@ attributes: { title: '{{ trans('general.create') }}', class: 'btn btn-primary', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1379,7 +1394,6 @@ }, attributes: { title: '{{ trans('button.add_maintenance') }}', - 'data-tooltip': true, } }, @endcan @@ -1393,7 +1407,6 @@ }, attributes: { title: '{{ trans('admin/hardware/general.custom_export') }}', - 'data-tooltip': true, } }, @@ -1405,7 +1418,6 @@ }, attributes: { title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - 'data-tooltip': true, } }, @@ -1423,7 +1435,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1438,7 +1449,6 @@ }, attributes: { title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - 'data-tooltip': true, } }, @@ -1457,7 +1467,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1478,7 +1487,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1499,7 +1507,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1541,7 +1548,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1562,7 +1568,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1596,7 +1601,6 @@ }, attributes: { title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - 'data-tooltip': true, } }, @@ -1616,7 +1620,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1637,7 +1640,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1658,7 +1660,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1679,7 +1680,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1700,7 +1700,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1721,7 +1720,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1735,7 +1733,6 @@ }, attributes: { title: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', - 'data-tooltip': true, } }, @@ -1754,7 +1751,6 @@ attributes: { class: 'btn btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1774,9 +1770,8 @@ window.location.href = '{{ route('licenses.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-primary', title: '{{ trans('general.create') }}', - 'data-tooltip': true, @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -1785,14 +1780,14 @@ @endcan btnExport: { - text: '{{ trans('general.export') }}', + text: '{{ trans('general.export_all_to_csv') }}', icon: 'fa-solid fa-file-csv', event () { window.location.href = '{{ route('licenses.export', ['category_id' => (isset($category)) ? $category->id :'' ]) }}'; }, attributes: { - title: '{{ trans('general.export') }}', - 'data-tooltip': true, + class: 'btn-primary', + title: '{{ trans('general.export_all_to_csv') }}', } }, @@ -1804,7 +1799,6 @@ }, attributes: { title: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', - 'data-tooltip': true, } }, @@ -1817,7 +1811,6 @@ }, attributes: { title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', - 'data-tooltip': true, } }, From 3c58a5dd3dc7794aa26e30f71515346a9d90eece Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 20:36:52 +0100 Subject: [PATCH 25/35] Fixed column selector --- resources/views/partials/bootstrap-table.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index ab36dde4db..2e753d0945 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -69,7 +69,7 @@ }, classes: 'table table-responsive table-striped snipe-table table-no-bordered', //buttonsPrefix: "btn", - buttonsClass: " tableButton", + buttonsClass: "tableButton btn-primary", // reorderableColumns: true, stickyHeader: true, stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10), From 7e23596ab87f1061111bc9d0ef06e904885744f8 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 23:09:33 +0100 Subject: [PATCH 26/35] Translate export to CSV --- resources/lang/en-US/general.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/en-US/general.php b/resources/lang/en-US/general.php index c59a2ebeb4..3c6738bbdc 100644 --- a/resources/lang/en-US/general.php +++ b/resources/lang/en-US/general.php @@ -398,6 +398,7 @@ return [ 'permissions' => 'Permissions', 'managed_ldap' => '(Managed via LDAP)', 'export' => 'Export', + 'export_all_to_csv' => 'Export all to CSV', 'ldap_sync' => 'LDAP Sync', 'ldap_user_sync' => 'LDAP User Sync', 'synchronize' => 'Synchronize', From 94a0a2f8bee6c40c744a69166561f240d3d477df Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 23:50:40 +0100 Subject: [PATCH 27/35] Fixed dropdown toggle --- .../views/partials/bootstrap-table.blade.php | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 2e753d0945..2120a6529d 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -67,41 +67,42 @@ 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }, - classes: 'table table-responsive table-striped snipe-table table-no-bordered', - //buttonsPrefix: "btn", - buttonsClass: "tableButton btn-primary", // reorderableColumns: true, + //buttonsPrefix: "btn", + addrbar: {{ (config('session.bs_table_addrbar') == 'true') ? 'true' : 'false'}}, // deeplink search phrases, sorting, etc + advancedSearch: data_with_default('advanced-search', true), + buttonsClass: "tableButton tableButton btn-primary", + buttonsOrder: ['refresh', 'export', 'print', 'fullscreen', 'columns'], + classes: 'table table-responsive table-striped snipe-table table-no-bordered', + clickToSelect: data_with_default('click-to-select', true), + cookie: true, + cookieExpire: '2y', + cookieStorage: '{{ config('session.bs_table_storage') }}', + iconsPrefix: 'fa', + maintainSelected: data_with_default('maintain-selected', true), + minimumCountColumns: data_with_default('minimum-count-columns', 2), + mobileResponsive: data_with_default('mobile-responsive', true), + pagination: data_with_default('pagination', true), + paginationFirstText: "{{ trans('general.first') }}", + paginationLastText: "{{ trans('general.last') }}", + paginationNextText: "{{ trans('general.next') }}", + paginationPreText: "{{ trans('general.previous') }}", + search: data_with_default('search', true), + searchHighlight: data_with_default('search-highlight', true), + showColumns: data_with_default('show-columns', true), + showColumnsToggleAll: data_with_default('show-columns-toggle-all', true), + showExport: data_with_default('show-export', true), + showFullscreen: data_with_default('show-fullscreen', true), + showPrint: data_with_default('show-print', true), + showRefresh: data_with_default('show-refresh', true), + showSearchClearButton: data_with_default('show-search-clear-button', true), + sortName: data_with_default('sort-name', 'created_at'), + sortOrder: data_with_default('sort-order', 'desc'), stickyHeader: true, stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10), stickyHeaderOffsetRight: parseInt($('body').css('padding-right'), 10), - undefinedText: '', - iconsPrefix: 'fa', - cookieStorage: '{{ config('session.bs_table_storage') }}', - cookie: true, - cookieExpire: '2y', - search: data_with_default('search', true), - advancedSearch: data_with_default('advanced-search', true), - searchHighlight: data_with_default('search-highlight', true), - clickToSelect: data_with_default('click-to-select', true), - showPrint: data_with_default('show-print', true), - showFullscreen: data_with_default('show-fullscreen', true), - showColumns: data_with_default('show-columns', true), - showExport: data_with_default('show-export', true), - showColumnsToggleAll: data_with_default('show-columns-toggle-all', true), - showRefresh: data_with_default('show-refresh', true), - pagination: data_with_default('pagination', true), - sortOrder: data_with_default('sort-order', 'desc'), - sortName: data_with_default('sort-name', 'created_at'), - minimumCountColumns: data_with_default('minimum-count-columns', 2), - mobileResponsive: data_with_default('mobile-responsive', true), - maintainSelected: data_with_default('maintain-selected', true), trimOnSearch: false, - showSearchClearButton: data_with_default('show-search-clear-button', true), - addrbar: {{ (config('session.bs_table_addrbar') == 'true') ? 'true' : 'false'}}, // deeplink search phrases, sorting, etc - paginationFirstText: "{{ trans('general.first') }}", - paginationLastText: "{{ trans('general.last') }}", - paginationPreText: "{{ trans('general.previous') }}", - paginationNextText: "{{ trans('general.next') }}", + undefinedText: '', pageList: ['10', '20', '30', '50', '100', '150', '200'{!! ((config('app.max_results') > 200) ? ",'500'" : '') !!}{!! ((config('app.max_results') > 500) ? ",'".config('app.max_results')."'" : '') !!}], pageSize: {{ (($snipeSettings->per_page!='') && ($snipeSettings->per_page > 0)) ? $snipeSettings->per_page : 20 }}, paginationVAlign: 'both', @@ -162,7 +163,6 @@ th.attr('data-toggle', 'tooltip'); th.attr('data-tooltip', 'true'); th.attr('data-placement', 'top'); - // th.attr('title', title) //this causes 'double-titles' which looks gross th.tooltip({container: 'body', title: title}); } @@ -174,13 +174,16 @@ title = tableButton.attr('title'); if (title) { - tableButton.attr('data-toggle', 'tooltip'); + console.log(title) + // Keep this commented out so that we don't interfere with the dropdown toggle for + // the dropdown toggle + // tableButton.attr('data-toggle', 'tooltip'); tableButton.attr('data-tooltip', 'true'); tableButton.attr('data-placement', 'top'); tableButton.tooltip({container: 'body', title: title}); } }); - + $('[data-tooltip="true"]').tooltip(); }, formatNoMatches: function () { From 3f69b70367aaf00424c24b822b7611a122e110cb Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 3 Oct 2025 23:54:38 +0100 Subject: [PATCH 28/35] Moved btn methods closer to the BS table --- .../views/partials/bootstrap-table.blade.php | 1062 ++++++++--------- 1 file changed, 529 insertions(+), 533 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 2120a6529d..ab789d6c1a 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -196,6 +196,535 @@ }); + // User table buttons + window.userButtons = () => ({ + @can('create', \App\Models\User::class) + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('users.create') }}'; + }, + attributes: { + title: '{{ trans('general.create') }}', + class: 'btn btn-primary', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + @endcan + + btnExport: { + text: '{{ trans('general.export_all_to_csv') }}', + icon: 'fa-solid fa-file-csv', + event () { + window.location.href = '{{ route('users.export') }}'; + }, + attributes: { + title: '{{ trans('general.export_all_to_csv') }}', + } + }, + + btnShowAdmins: { + text: '{{ trans('general.show_admins') }}', + icon: 'fa-solid fa-crown{{ (request()->input('admins') == "true") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('admins') == "true") ? route('users.index') : route('users.index', ['admins' => 'true']) }}'; + }, + attributes: { + title: '{{ trans('general.show_admins') }}', + } + }, + + btnShowDeleted: { + text: '{{ (request()->input('status') == "deleted") ?trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}', + event () { + window.location.href = '{{ (request()->input('status') == "deleted") ? route('users.index') : route('users.index', ['status' => 'deleted']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + + } + }, + + }); // end user table buttons + + + @can('create', \App\Models\Company::class) + // Company table buttons + window.companyButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('companies.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + + }); // End company table buttons + @endcan + + + // Asset table buttons + window.assetButtons = () => ({ + @can('create', \App\Models\Asset::class) + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('hardware.create') }}'; + }, + attributes: { + title: '{{ trans('general.create') }}', + class: 'btn btn-primary', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + @endcan + + @can('update', \App\Models\Asset::class) + btnAddMaintenance: { + text: '{{ trans('button.add_maintenance') }}', + icon: 'fa-solid fa-screwdriver-wrench', + event () { + window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; + }, + attributes: { + title: '{{ trans('button.add_maintenance') }}', + } + }, + @endcan + + + btnExport: { + text: '{{ trans('admin/hardware/general.custom_export') }}', + icon: 'fa-solid fa-file-csv', + event () { + window.location.href = '{{ route('reports/custom') }}'; + }, + attributes: { + title: '{{ trans('admin/hardware/general.custom_export') }}', + } + }, + + btnShowDeleted: { + text: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', + icon: 'fa-solid fa-trash {{ (request()->input('status') == "Deleted") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('status') == "Deleted") ? route('hardware.index') : route('hardware.index', ['status' => 'Deleted']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', + + } + }, + }); + + @can('create', \App\Models\Location::class) + // Location table buttons + window.locationButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('locations.create') }}'; + }, + attributes: { + class: 'btn btn-default', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + + btnShowDeleted: { + text: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}', + event () { + window.location.href = '{{ (request()->input('status') == "deleted") ? route('locations.index') : route('locations.index', ['status' => 'deleted']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + + } + }, + }); + @endcan + + @can('create', \App\Models\Accessory::class) + // Accessory table buttons + window.accessoryButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('accessories.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\Depreciation::class) + // Accessory table buttons + window.depreciationButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('depreciations.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\CustomField::class) + // Accessory table buttons + window.customFieldButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('fields.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + + @can('create', \App\Models\CustomFieldset::class) + // Accessory table buttons + window.customFieldsetButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('fieldsets.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\Component::class) + // Compoment table buttons + window.componentButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('components.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\Consumable::class) + // Consumable table buttons + window.consumableButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('consumables.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\Manufacturer::class) + // Consumable table buttons + window.manufacturerButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('manufacturers.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + }, + + btnShowDeleted: { + text: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', + icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('status') == "deleted") ? route('manufacturers.index') : route('manufacturers.index', ['status' => 'deleted']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', + + } + }, + }, + }); + @endcan + + @can('create', \App\Models\Supplier::class) + // Consumable table buttons + window.supplierButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('suppliers.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\Department::class) + // Department table buttons + window.departmentButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('departments.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\CustomField::class) + // Custom Field table buttons + window.departmentButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('departments.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('update', \App\Models\Asset::class) + // Custom Field table buttons + window.maintenanceButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\Category::class) + // Custom Field table buttons + window.categoryButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('categories.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + @can('create', \App\Models\AssetModel::class) + // Custom Field table buttons + window.modelButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('models.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + btnShowDeleted: { + text: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', + icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('status') == "deleted") ? route('models.index') : route('models.index', ['status' => 'deleted']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', + + } + }, + }); + @endcan + + @can('create', \App\Models\Statuslabel::class) + // Status label table buttons + window.statuslabelButtons = () => ({ + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('statuslabels.create') }}'; + }, + attributes: { + class: 'btn btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + } + }, + }); + @endcan + + + // License table buttons + window.licenseButtons = () => ({ + @can('create', \App\Models\License::class) + btnAdd: { + text: '{{ trans('general.create') }}', + icon: 'fa fa-plus', + event () { + window.location.href = '{{ route('licenses.create') }}'; + }, + attributes: { + class: 'btn-primary', + title: '{{ trans('general.create') }}', + @if ($snipeSettings->shortcuts_enabled == 1) + accesskey: 'n' + @endif + }, + }, + @endcan + + btnExport: { + text: '{{ trans('general.export_all_to_csv') }}', + icon: 'fa-solid fa-file-csv', + event () { + window.location.href = '{{ route('licenses.export', ['category_id' => (isset($category)) ? $category->id :'' ]) }}'; + }, + attributes: { + class: 'btn-primary', + title: '{{ trans('general.export_all_to_csv') }}', + } + }, + + btnShowExpiring: { + text: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', + icon: 'fas fa-clock {{ (request()->input('status') == "expiring") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('status') == "expiring") ? route('licenses.index') : route('licenses.index', ['status' => 'expiring']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', + + } + }, + + btnShowInactive: { + text: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', + icon: 'fas fa-history {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}', + event () { + window.location.href = '{{ (request()->input('status') == "inactive") ? route('licenses.index') : route('licenses.index', ['status' => 'inactive']) }}'; + }, + attributes: { + title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', + + } + }, + }); + + @@ -1290,539 +1819,6 @@ }); }); - - // User table buttons - window.userButtons = () => ({ - @can('create', \App\Models\User::class) - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('users.create') }}'; - }, - attributes: { - title: '{{ trans('general.create') }}', - class: 'btn btn-primary', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - @endcan - - btnExport: { - text: '{{ trans('general.export_all_to_csv') }}', - icon: 'fa-solid fa-file-csv', - event () { - window.location.href = '{{ route('users.export') }}'; - }, - attributes: { - title: '{{ trans('general.export_all_to_csv') }}', - } - }, - - btnShowAdmins: { - text: '{{ trans('general.show_admins') }}', - icon: 'fa-solid fa-crown{{ (request()->input('admins') == "true") ? ' text-danger' : '' }}', - event () { - window.location.href = '{{ (request()->input('admins') == "true") ? route('users.index') : route('users.index', ['admins' => 'true']) }}'; - }, - attributes: { - title: '{{ trans('general.show_admins') }}', - } - }, - - btnShowDeleted: { - text: '{{ (request()->input('status') == "deleted") ?trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}', - event () { - window.location.href = '{{ (request()->input('status') == "deleted") ? route('users.index') : route('users.index', ['status' => 'deleted']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - - } - }, - - }); // end user table buttons - - - @can('create', \App\Models\Company::class) - // Company table buttons - window.companyButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('companies.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - - }); // End company table buttons - @endcan - - - // Asset table buttons - window.assetButtons = () => ({ - @can('create', \App\Models\Asset::class) - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('hardware.create') }}'; - }, - attributes: { - title: '{{ trans('general.create') }}', - class: 'btn btn-primary', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - @endcan - - @can('update', \App\Models\Asset::class) - btnAddMaintenance: { - text: '{{ trans('button.add_maintenance') }}', - icon: 'fa-solid fa-screwdriver-wrench', - event () { - window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; - }, - attributes: { - title: '{{ trans('button.add_maintenance') }}', - } - }, - @endcan - - - btnExport: { - text: '{{ trans('admin/hardware/general.custom_export') }}', - icon: 'fa-solid fa-file-csv', - event () { - window.location.href = '{{ route('reports/custom') }}'; - }, - attributes: { - title: '{{ trans('admin/hardware/general.custom_export') }}', - } - }, - - btnShowDeleted: { - text: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "Deleted") ? ' text-danger' : '' }}', - event () { - window.location.href = '{{ (request()->input('status') == "Deleted") ? route('hardware.index') : route('hardware.index', ['status' => 'Deleted']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - - } - }, - }); - - @can('create', \App\Models\Location::class) - // Location table buttons - window.locationButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('locations.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - - btnShowDeleted: { - text: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}', - event () { - window.location.href = '{{ (request()->input('status') == "deleted") ? route('locations.index') : route('locations.index', ['status' => 'deleted']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - - } - }, - }); - @endcan - - @can('create', \App\Models\Accessory::class) - // Accessory table buttons - window.accessoryButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('accessories.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\Depreciation::class) - // Accessory table buttons - window.depreciationButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('depreciations.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\CustomField::class) - // Accessory table buttons - window.customFieldButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('fields.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - - @can('create', \App\Models\CustomFieldset::class) - // Accessory table buttons - window.customFieldsetButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('fieldsets.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\Component::class) - // Compoment table buttons - window.componentButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('components.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\Consumable::class) - // Consumable table buttons - window.consumableButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('consumables.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\Manufacturer::class) - // Consumable table buttons - window.manufacturerButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('manufacturers.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - }, - - btnShowDeleted: { - text: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : '' }}', - event () { - window.location.href = '{{ (request()->input('status') == "deleted") ? route('manufacturers.index') : route('manufacturers.index', ['status' => 'deleted']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - - } - }, - }, - }); - @endcan - - @can('create', \App\Models\Supplier::class) - // Consumable table buttons - window.supplierButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('suppliers.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\Department::class) - // Department table buttons - window.departmentButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('departments.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\CustomField::class) - // Custom Field table buttons - window.departmentButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('departments.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('update', \App\Models\Asset::class) - // Custom Field table buttons - window.maintenanceButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\Category::class) - // Custom Field table buttons - window.categoryButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('categories.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - @can('create', \App\Models\AssetModel::class) - // Custom Field table buttons - window.modelButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('models.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - btnShowDeleted: { - text: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : '' }}', - event () { - window.location.href = '{{ (request()->input('status') == "deleted") ? route('models.index') : route('models.index', ['status' => 'deleted']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', - - } - }, - }); - @endcan - - @can('create', \App\Models\Statuslabel::class) - // Status label table buttons - window.statuslabelButtons = () => ({ - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('statuslabels.create') }}'; - }, - attributes: { - class: 'btn btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - } - }, - }); - @endcan - - - // License table buttons - window.licenseButtons = () => ({ - @can('create', \App\Models\License::class) - btnAdd: { - text: '{{ trans('general.create') }}', - icon: 'fa fa-plus', - event () { - window.location.href = '{{ route('licenses.create') }}'; - }, - attributes: { - class: 'btn-primary', - title: '{{ trans('general.create') }}', - @if ($snipeSettings->shortcuts_enabled == 1) - accesskey: 'n' - @endif - }, - }, - @endcan - - btnExport: { - text: '{{ trans('general.export_all_to_csv') }}', - icon: 'fa-solid fa-file-csv', - event () { - window.location.href = '{{ route('licenses.export', ['category_id' => (isset($category)) ? $category->id :'' ]) }}'; - }, - attributes: { - class: 'btn-primary', - title: '{{ trans('general.export_all_to_csv') }}', - } - }, - - btnShowExpiring: { - text: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', - icon: 'fas fa-clock {{ (request()->input('status') == "expiring") ? ' text-danger' : '' }}', - event () { - window.location.href = '{{ (request()->input('status') == "expiring") ? route('licenses.index') : route('licenses.index', ['status' => 'expiring']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', - - } - }, - - btnShowInactive: { - text: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', - icon: 'fas fa-history {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}', - event () { - window.location.href = '{{ (request()->input('status') == "inactive") ? route('licenses.index') : route('licenses.index', ['status' => 'inactive']) }}'; - }, - attributes: { - title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', - - } - }, - }); - - - - - $(function() { // This handles the search box highlighting on both ajax and client-side From 70eccceab34fc41f590d5a89d5c8c4a548f02931 Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 00:18:09 +0100 Subject: [PATCH 29/35] Updated button class for add new --- .../views/partials/bootstrap-table.blade.php | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index ab789d6c1a..110515a7b6 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -68,11 +68,21 @@ } }, // reorderableColumns: true, - //buttonsPrefix: "btn", + // buttonsPrefix: "btn", addrbar: {{ (config('session.bs_table_addrbar') == 'true') ? 'true' : 'false'}}, // deeplink search phrases, sorting, etc advancedSearch: data_with_default('advanced-search', true), - buttonsClass: "tableButton tableButton btn-primary", - buttonsOrder: ['refresh', 'export', 'print', 'fullscreen', 'columns'], + buttonsClass: "tableButton tableButton btn-primary hidden-print", + buttonsOrder: [ + 'columns', + 'btnAdd', + 'btnShowDeleted', + 'btnShowAdmins', + 'btnExport', + 'export', + 'print', + 'fullscreen', + 'refresh', + ], classes: 'table table-responsive table-striped snipe-table table-no-bordered', clickToSelect: data_with_default('click-to-select', true), cookie: true, @@ -172,18 +182,21 @@ toolbar_buttons.each(function (index, element) { tableButton = $(element); title = tableButton.attr('title'); + override_class = tableButton.attr('class'); if (title) { - console.log(title) - // Keep this commented out so that we don't interfere with the dropdown toggle for - // the dropdown toggle - // tableButton.attr('data-toggle', 'tooltip'); + // console.log(title) + // tableButton.attr('data-toggle', 'tooltip'); // Keep this commented out so that we don't interfere with the dropdown toggle for tableButton.attr('data-tooltip', 'true'); - tableButton.attr('data-placement', 'top'); - tableButton.tooltip({container: 'body', title: title}); + tableButton.attr('data-placement', 'auto'); + + // This handles the case where we want a different color button than the default + if ((override_class) && ((override_class.indexOf('btn-info') >= 0)) || (override_class.indexOf('btn-danger') >= 0)) { + tableButton.removeClass('btn-primary'); + } } }); - $('[data-tooltip="true"]').tooltip(); + // $('[data-tooltip="true"]').tooltip(); }, formatNoMatches: function () { @@ -207,7 +220,7 @@ }, attributes: { title: '{{ trans('general.create') }}', - class: 'btn btn-primary', + class: 'btn-info', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -262,7 +275,7 @@ window.location.href = '{{ route('companies.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -285,7 +298,7 @@ }, attributes: { title: '{{ trans('general.create') }}', - class: 'btn btn-primary', + class: 'btn-info', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @endif @@ -301,6 +314,7 @@ window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; }, attributes: { + class: 'btn-info', title: '{{ trans('button.add_maintenance') }}', } }, @@ -341,7 +355,7 @@ window.location.href = '{{ route('locations.create') }}'; }, attributes: { - class: 'btn btn-default', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -373,7 +387,7 @@ window.location.href = '{{ route('accessories.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -393,7 +407,7 @@ window.location.href = '{{ route('depreciations.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -413,7 +427,7 @@ window.location.href = '{{ route('fields.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -434,7 +448,7 @@ window.location.href = '{{ route('fieldsets.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -454,7 +468,7 @@ window.location.href = '{{ route('components.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -474,7 +488,7 @@ window.location.href = '{{ route('consumables.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -494,7 +508,7 @@ window.location.href = '{{ route('manufacturers.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -526,7 +540,7 @@ window.location.href = '{{ route('suppliers.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -546,7 +560,7 @@ window.location.href = '{{ route('departments.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -566,7 +580,7 @@ window.location.href = '{{ route('departments.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -586,7 +600,7 @@ window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -606,7 +620,7 @@ window.location.href = '{{ route('categories.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -657,7 +671,7 @@ window.location.href = '{{ route('statuslabels.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -678,7 +692,7 @@ window.location.href = '{{ route('licenses.create') }}'; }, attributes: { - class: 'btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' From dfb7c7306941ba96b26ab401e3144a0841405e35 Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 00:31:06 +0100 Subject: [PATCH 30/35] Added column search to users --- resources/views/users/index.blade.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php index 93cf9804ec..bfd0e56554 100755 --- a/resources/views/users/index.blade.php +++ b/resources/views/users/index.blade.php @@ -43,6 +43,7 @@ data-toolbar="#userBulkEditToolbar" data-bulk-button-id="#bulkUserEditButton" data-bulk-form-id="#usersBulkForm" + data-show-columns-search="true" id="usersTable" data-buttons="userButtons" class="table table-striped snipe-table" From 59518ca2c50c9eb5bb095ab1f1db9f289d49408f Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 00:31:17 +0100 Subject: [PATCH 31/35] Small style updates --- .../views/partials/bootstrap-table.blade.php | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 110515a7b6..2152db3be1 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -251,12 +251,13 @@ }, btnShowDeleted: { - text: '{{ (request()->input('status') == "deleted") ?trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}', + text: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', + icon: 'fa-solid fa-trash', event () { window.location.href = '{{ (request()->input('status') == "deleted") ? route('users.index') : route('users.index', ['status' => 'deleted']) }}'; }, attributes: { + class: '{{ (request()->input('status') == "deleted") ? ' btn-danger' : '' }}', title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', } @@ -306,7 +307,7 @@ }, @endcan - @can('update', \App\Models\Asset::class) + @can('update', \App\Models\Asset::class) btnAddMaintenance: { text: '{{ trans('button.add_maintenance') }}', icon: 'fa-solid fa-screwdriver-wrench', @@ -334,11 +335,12 @@ btnShowDeleted: { text: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "Deleted") ? ' text-danger' : '' }}', + icon: 'fa-solid fa-trash', event () { window.location.href = '{{ (request()->input('status') == "Deleted") ? route('hardware.index') : route('hardware.index', ['status' => 'Deleted']) }}'; }, attributes: { + class: '{{ (request()->input('status') == "Deleted") ? ' btn-danger' : '' }}', title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', } @@ -365,7 +367,7 @@ btnShowDeleted: { text: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}', + icon: 'fa-solid fa-trash', event () { window.location.href = '{{ (request()->input('status') == "deleted") ? route('locations.index') : route('locations.index', ['status' => 'deleted']) }}'; }, @@ -517,11 +519,12 @@ btnShowDeleted: { text: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : '' }}', + icon: 'fa-solid fa-trash', event () { window.location.href = '{{ (request()->input('status') == "deleted") ? route('manufacturers.index') : route('manufacturers.index', ['status' => 'deleted']) }}'; }, attributes: { + class: '{{ (request()->input('status') == "Deleted") ? ' btn-danger' : '' }}', title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}', } @@ -570,7 +573,7 @@ }); @endcan - @can('create', \App\Models\CustomField::class) + @can('create', \App\Models\Department::class) // Custom Field table buttons window.departmentButtons = () => ({ btnAdd: { @@ -640,7 +643,7 @@ window.location.href = '{{ route('models.create') }}'; }, attributes: { - class: 'btn btn-primary', + class: 'btn-info', title: '{{ trans('general.create') }}', @if ($snipeSettings->shortcuts_enabled == 1) accesskey: 'n' @@ -649,11 +652,12 @@ }, btnShowDeleted: { text: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', - icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : '' }}', + icon: 'fa-solid fa-trash', event () { window.location.href = '{{ (request()->input('status') == "deleted") ? route('models.index') : route('models.index', ['status' => 'deleted']) }}'; }, attributes: { + class: '{{ (request()->input('status') == "deleted") ? ' btn-danger' : '' }}', title: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}', } From 224642fcb529b2b5a110109b9fbf95cf428ffc7a Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 01:04:25 +0100 Subject: [PATCH 32/35] Removed funky search cookie --- resources/views/hardware/index.blade.php | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/views/hardware/index.blade.php b/resources/views/hardware/index.blade.php index 444c807188..fded1c3d14 100755 --- a/resources/views/hardware/index.blade.php +++ b/resources/views/hardware/index.blade.php @@ -63,7 +63,6 @@ data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}" data-cookie-id-table="{{ request()->has('status') ? e(request()->input('status')) : '' }}assetsListingTable" data-id-table="{{ request()->has('status') ? e(request()->input('status')) : '' }}assetsListingTable" - data-search-text="{{ e(Session::get('search')) }}" data-side-pagination="server" data-show-footer="true" data-sort-order="asc" From 2467e823a5a9eb256f75167acfcbf11f72526ec7 Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 01:06:56 +0100 Subject: [PATCH 33/35] Reordered buttons --- resources/views/partials/bootstrap-table.blade.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 2152db3be1..97261a6c16 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -77,11 +77,12 @@ 'btnAdd', 'btnShowDeleted', 'btnShowAdmins', + 'refresh', 'btnExport', 'export', 'print', 'fullscreen', - 'refresh', + 'advancedSearch', ], classes: 'table table-responsive table-striped snipe-table table-no-bordered', clickToSelect: data_with_default('click-to-select', true), @@ -185,19 +186,21 @@ override_class = tableButton.attr('class'); if (title) { - // console.log(title) - // tableButton.attr('data-toggle', 'tooltip'); // Keep this commented out so that we don't interfere with the dropdown toggle for + // Keep this commented out so that we don't interfere with the dropdown toggle for columns, etc + // tableButton.attr('data-toggle', 'tooltip'); tableButton.attr('data-tooltip', 'true'); tableButton.attr('data-placement', 'auto'); + // This prevents the slight button jitter on the mouseovees on the dashboard + tableButton.tooltip({container: 'body', title: title}); + // This handles the case where we want a different color button than the default if ((override_class) && ((override_class.indexOf('btn-info') >= 0)) || (override_class.indexOf('btn-danger') >= 0)) { tableButton.removeClass('btn-primary'); } } }); - // $('[data-tooltip="true"]').tooltip(); - + }, formatNoMatches: function () { return '{{ trans('table.no_matching_records') }}'; @@ -315,7 +318,6 @@ window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}'; }, attributes: { - class: 'btn-info', title: '{{ trans('button.add_maintenance') }}', } }, From 4e1ef40c05065ee97d01756a3ea89d669ee1f913 Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 13:16:46 +0100 Subject: [PATCH 34/35] Updated active button colors --- resources/views/partials/bootstrap-table.blade.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 97261a6c16..32f9207d05 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -721,11 +721,12 @@ btnShowExpiring: { text: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', - icon: 'fas fa-clock {{ (request()->input('status') == "expiring") ? ' text-danger' : '' }}', + icon: 'fas fa-clock', event () { window.location.href = '{{ (request()->input('status') == "expiring") ? route('licenses.index') : route('licenses.index', ['status' => 'expiring']) }}'; }, attributes: { + class: "{{ (request()->input('status') == "expiring") ? ' btn-warning' : '' }}", title: '{{ (request()->input('status') == "expiring") ? trans('general.list_all') : trans('general.show_expiring') }}', } @@ -733,11 +734,12 @@ btnShowInactive: { text: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', - icon: 'fas fa-history {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}', + icon: 'fas fa-history', event () { window.location.href = '{{ (request()->input('status') == "inactive") ? route('licenses.index') : route('licenses.index', ['status' => 'inactive']) }}'; }, attributes: { + class: "{{ (request()->input('status') == "inactive") ? ' btn-warning' : '' }}", title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}', } From fd8a8b29b1fb71927c51a8b292427cf31243a5fe Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 4 Oct 2025 13:18:51 +0100 Subject: [PATCH 35/35] Added inactive and expired to licenses table listing --- resources/views/partials/bootstrap-table.blade.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 32f9207d05..5af85992a5 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -77,6 +77,8 @@ 'btnAdd', 'btnShowDeleted', 'btnShowAdmins', + 'btnShowExpiring', + 'btnShowInactive', 'refresh', 'btnExport', 'export',