Compare commits

...

19 commits

Author SHA1 Message Date
c0a1da23ec save 2025-04-30 21:32:48 +02:00
snipe
049a669186 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:46:16 +01:00
snipe
a0358e32d7 Removed escaping
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 16:46:06 +01:00
snipe
d29f13bae9 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:26:38 +01:00
snipe
c2023c5c56 Ampersand showing in Custom fields [sc-29051]
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 16:25:44 +01:00
snipe
c758355df9 Merge remote-tracking branch 'origin/develop' 2025-04-30 16:14:34 +01:00
snipe
43c310c82d
Merge pull request #16531 from akemidx/bug/sc-28715
FIXED: Purchase Cost Column Always Shown
2025-04-30 15:54:31 +01:00
snipe
79d97a83af Merge remote-tracking branch 'origin/develop' 2025-04-30 15:48:38 +01:00
snipe
939a0c44dc
Merge pull request #16826 from Godmartinz/fix_multiple_inline_label_field_options
Reworked fix for for 24mm_D label indent errror
2025-04-30 15:47:57 +01:00
snipe
85bd47c240 Merge remote-tracking branch 'origin/develop' 2025-04-30 15:35:10 +01:00
snipe
2b9cf1663b
Merge pull request #16837 from grokability/fmcs_scoping_improvements
Small improvements to scoped views
2025-04-30 15:33:53 +01:00
snipe
0a29e90701 Smal improvements to scoping displays
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 15:24:42 +01:00
snipe
d1be13e7d4 Added button text to translations
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:32:29 +01:00
snipe
049a777ca8 Added buttons to dashboard
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:32:20 +01:00
snipe
0dcaa83a3e Nicer breadcrumb
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:22:13 +01:00
snipe
db706269e6 Fixed validation message
Signed-off-by: snipe <snipe@snipe.net>
2025-04-30 14:22:06 +01:00
Godfrey M
2e0913bb3b remove unused method 2025-04-29 10:49:19 -07:00
Godfrey M
851ae46ea9 reworked fix for for 24mm_D label indent errior 2025-04-29 10:45:29 -07:00
akemidx
e408b902f0 removing depreciation from purchase cost (unneeded, should go elsewhere if wanted) 2025-03-18 16:38:44 -04:00
18 changed files with 90 additions and 41 deletions

View file

@ -26,6 +26,10 @@
"description": "URL where your Snipe-IT install will be available at.", "description": "URL where your Snipe-IT install will be available at.",
"value": "https://your-app-name.herokuapp.com" "value": "https://your-app-name.herokuapp.com"
}, },
"LABEL_URL": {
"description": "Labels",
"value": "https://your-app-name.herokuapp.com"
},
"APP_TIMEZONE": { "APP_TIMEZONE": {
"description": "Which timezone do you want to use for your install? (http://php.net/manual/en/timezones.php)", "description": "Which timezone do you want to use for your install? (http://php.net/manual/en/timezones.php)",
"value": "UTC" "value": "UTC"

View file

@ -5,6 +5,8 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Transformers\ActionlogsTransformer; use App\Http\Transformers\ActionlogsTransformer;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Company;
use App\Models\Setting;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@ -18,10 +20,11 @@ class ReportsController extends Controller
*/ */
public function index(Request $request) : JsonResponse | array public function index(Request $request) : JsonResponse | array
{ {
$this->authorize('reports.view'); $this->authorize('activity.view');
$actionlogs = Actionlog::with('item', 'user', 'adminuser', 'target', 'location'); $actionlogs = Actionlog::with('item', 'user', 'adminuser', 'target', 'location');
if ($request->filled('search')) { if ($request->filled('search')) {
$actionlogs = $actionlogs->TextSearch(e($request->input('search'))); $actionlogs = $actionlogs->TextSearch(e($request->input('search')));
} }

View file

@ -238,8 +238,8 @@ class CustomFieldsController extends Controller
$display_in_user_view = '0'; $display_in_user_view = '0';
} }
$field->name = trim(e($request->get("name"))); $field->name = trim($request->get("name"));
$field->element = e($request->get("element")); $field->element = $request->get("element");
$field->field_values = $request->get("field_values"); $field->field_values = $request->get("field_values");
$field->created_by = auth()->id(); $field->created_by = auth()->id();
$field->help_text = $request->get("help_text"); $field->help_text = $request->get("help_text");
@ -254,9 +254,9 @@ class CustomFieldsController extends Controller
$field->display_audit = $request->get("display_audit", 0); $field->display_audit = $request->get("display_audit", 0);
if ($request->get('format') == 'CUSTOM REGEX') { if ($request->get('format') == 'CUSTOM REGEX') {
$field->format = e($request->get('custom_format')); $field->format = $request->get('custom_format');
} else { } else {
$field->format = e($request->get('format')); $field->format = $request->get('format');
} }
if ($field->element == 'checkbox' || $field->element == 'radio'){ if ($field->element == 'checkbox' || $field->element == 'radio'){

View file

@ -485,7 +485,7 @@ class ReportsController extends Controller
$header[] = trans('admin/hardware/table.purchase_date'); $header[] = trans('admin/hardware/table.purchase_date');
} }
if (($request->filled('purchase_cost')) || ($request->filled('depreciation'))) { if ($request->filled('purchase_cost')) {
$header[] = trans('admin/hardware/table.purchase_cost'); $header[] = trans('admin/hardware/table.purchase_cost');
} }

View file

@ -70,27 +70,38 @@ class TZe_24mm_D extends TZe_24mm
} }
foreach ($record->get('fields') as $field) { foreach ($record->get('fields') as $field) {
// Write label and value on the same line if (!empty($field['label']) && $field['label'] !== "\u{200B}") {
// Calculate label width with proportional character spacing // Write label and value on the same line
$labelWidth = $pdf->GetStringWidth($field['label'], 'freemono', '', self::LABEL_SIZE); // Calculate label width with proportional character spacing
$charCount = strlen($field['label']); $labelWidth = $pdf->GetStringWidth($field['label'], 'freemono', '', self::LABEL_SIZE);
$spacingPerChar = 0.5; $charCount = strlen($field['label']);
$totalSpacing = $charCount * $spacingPerChar; $spacingPerChar = 0.5;
$adjustedWidth = $labelWidth + $totalSpacing; $totalSpacing = $charCount * $spacingPerChar;
$adjustedWidth = $labelWidth + $totalSpacing;
static::writeText( static::writeText(
$pdf, $field['label'], $pdf, $field['label'],
$currentX, $currentY, $currentX, $currentY,
'freemono', 'B', self::LABEL_SIZE, 'L', 'freemono', 'B', self::LABEL_SIZE, 'L',
$adjustedWidth, self::LABEL_SIZE, true, 0, $spacingPerChar $adjustedWidth, self::LABEL_SIZE, true, 0, $spacingPerChar
); );
static::writeText( static::writeText(
$pdf, $field['value'], $pdf, $field['value'],
$currentX + $adjustedWidth + 2, $currentY, $currentX + $adjustedWidth + 2, $currentY,
'freemono', 'B', self::FIELD_SIZE, 'L', 'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth - $adjustedWidth - 2, self::FIELD_SIZE, true, 0, 0.3 $usableWidth - $adjustedWidth - 2, self::FIELD_SIZE, true, 0, 0.3
); );
} else {
// Label is empty, so write value only.
static::writeText(
$pdf, $field['value'],
$currentX, $currentY, // No offset
'freemono', 'B', self::FIELD_SIZE, 'L',
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
);
}
$currentY += max(self::LABEL_SIZE, self::FIELD_SIZE) + self::FIELD_MARGIN; $currentY += max(self::LABEL_SIZE, self::FIELD_SIZE) + self::FIELD_MARGIN;
} }

View file

@ -33,7 +33,7 @@ class LocationPresenter extends Presenter
'switchable' => true, 'switchable' => true,
'title' => trans('general.company'), 'title' => trans('general.company'),
'visible' => false, 'visible' => false,
'formatter' => 'locationCompanyObjFilterFormatter' 'formatter' => 'companiesLinkObjFormatter'
], ],
[ [
'field' => 'name', 'field' => 'name',

View file

@ -168,6 +168,15 @@ class AuthServiceProvider extends ServiceProvider
} }
}); });
// -----------------------------------------
// Activity
// -----------------------------------------
Gate::define('activity.view', function ($user) {
if (($user->hasAccess('reports.view')) || ($user->hasAccess('admin'))) {
return true;
}
});
// ----------------------------------------- // -----------------------------------------
// Self // Self
// ----------------------------------------- // -----------------------------------------

View file

@ -385,6 +385,7 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('locations.edit', fn (Trail $trail, Location $location) => Breadcrumbs::for('locations.edit', fn (Trail $trail, Location $location) =>
$trail->parent('locations.index', route('locations.index')) $trail->parent('locations.index', route('locations.index'))
->push($location->name, route('locations.show', $location))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $location->name]), route('locations.edit', $location)) ->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $location->name]), route('locations.edit', $location))
); );

View file

@ -142,6 +142,9 @@ class Label implements View
case 'location': case 'location':
$barcode2DTarget = route('locations.show', $asset->location_id); $barcode2DTarget = route('locations.show', $asset->location_id);
break; break;
case 'custom_url_hardware_id':
$barcode2DTarget = route('hardware.show', $asset);
break;
case 'hardware_id': case 'hardware_id':
default: default:
$barcode2DTarget = route('hardware.show', $asset); $barcode2DTarget = route('hardware.show', $asset);
@ -177,10 +180,13 @@ class Label implements View
// The end result of this will be in this format: // The end result of this will be in this format:
// {labelOne} {valueOne} | {labelTwo} {valueTwo} | {labelThree} {valueThree} // {labelOne} {valueOne} | {labelTwo} {valueTwo} | {labelThree} {valueThree}
$previous['value'] = trim(implode(' | ', [ $previous['value'] = trim(implode(' | ', [
implode(' ', [null, $previous['value']]), implode(' ', [$previous['label'], $previous['value']]),
implode(' ', [$current['label'], $current['value']]), implode(' ', [$current['label'], $current['value']]),
])); ]));
// We'll set the label to an empty string since we
// injected the label into the value field above.
$previous['label'] = '';
return $previous; return $previous;
}); });

View file

@ -74,6 +74,7 @@ return [
*/ */
'url' => env('APP_URL', 'http://localhost'), 'url' => env('APP_URL', 'http://localhost'),
'label_url' => env('LABEL_URL', 'http://localhost'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View file

@ -390,6 +390,8 @@ return [
'new_license' => 'New License', 'new_license' => 'New License',
'new_accessory' => 'New Accessory', 'new_accessory' => 'New Accessory',
'new_consumable' => 'New Consumable', 'new_consumable' => 'New Consumable',
'new_component' => 'New Component',
'new_user' => 'New User',
'collapse' => 'Collapse', 'collapse' => 'Collapse',
'assigned' => 'Assigned', 'assigned' => 'Assigned',
'asset_count' => 'Asset Count', 'asset_count' => 'Asset Count',

View file

@ -172,6 +172,7 @@ return [
'url' => 'The :attribute field must be a valid URL.', 'url' => 'The :attribute field must be a valid URL.',
'ulid' => 'The :attribute field must be a valid ULID.', 'ulid' => 'The :attribute field must be a valid ULID.',
'uuid' => 'The :attribute field must be a valid UUID.', 'uuid' => 'The :attribute field must be a valid UUID.',
'fmcs_location' => 'Full multiple company support and location scoping is enabled in the Admin Settings, and the selected location and selected company are not compatible.',
/* /*

View file

@ -172,26 +172,36 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-3"> <div class="col-md-2">
@can('create', \App\Models\Asset::class) @can('create', \App\Models\Asset::class)
<a class="btn bg-teal" style="width: 100%" href="{{ route('hardware.create') }}">{{ trans('general.new_asset') }}</a> <a class="btn bg-teal" style="width: 100%" href="{{ route('hardware.create') }}">{{ trans('general.new_asset') }}</a>
@endcan @endcan
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
@can('create', \App\Models\License::class) @can('create', \App\Models\License::class)
<a class="btn bg-maroon" style="width: 100%" href="{{ route('licenses.create') }}">{{ trans('general.new_license') }}</a> <a class="btn bg-maroon" style="width: 100%" href="{{ route('licenses.create') }}">{{ trans('general.new_license') }}</a>
@endcan @endcan
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
@can('create', \App\Models\Accessory::class) @can('create', \App\Models\Accessory::class)
<a class="btn bg-orange" style="width: 100%" href="{{ route('accessories.create') }}">{{ trans('general.new_accessory') }}</a> <a class="btn bg-orange" style="width: 100%" href="{{ route('accessories.create') }}">{{ trans('general.new_accessory') }}</a>
@endcan @endcan
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
@can('create', \App\Models\Consumable::class) @can('create', \App\Models\Consumable::class)
<a class="btn bg-purple" style="width: 100%" href="{{ route('consumables.create') }}">{{ trans('general.new_consumable') }}</a> <a class="btn bg-purple" style="width: 100%" href="{{ route('consumables.create') }}">{{ trans('general.new_consumable') }}</a>
@endcan @endcan
</div> </div>
<div class="col-md-2">
@can('create', \App\Models\Component::class)
<a class="btn bg-yellow" style="width: 100%" href="{{ route('components.create') }}">{{ trans('general.new_component') }}</a>
@endcan
</div>
<div class="col-md-2">
@can('create', \App\Models\User::class)
<a class="btn bg-light-blue" style="width: 100%" href="{{ route('users.create') }}">{{ trans('general.new_user') }}</a>
@endcan
</div>
</div> </div>
</div> </div>
</div> </div>
@ -282,7 +292,7 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
@if ($snipeSettings->full_multiple_companies_support=='1') @if ((($snipeSettings->scope_locations_fmcs!='1') && ($snipeSettings->full_multiple_companies_support=='1')))
<!-- Companies --> <!-- Companies -->
<div class="box box-default"> <div class="box box-default">
<div class="box-header with-border"> <div class="box-header with-border">

View file

@ -217,7 +217,7 @@
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: "{{ config('app.url') }}/models/" + modelid + "/custom_fields", url: "{{ config('app.label_url') }}/models/" + modelid + "/custom_fields",
headers: { headers: {
"X-Requested-With": 'XMLHttpRequest', "X-Requested-With": 'XMLHttpRequest',
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content') "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')
@ -260,7 +260,7 @@
if (status_id != '') { if (status_id != '') {
$(".status_spinner").css("display", "inline"); $(".status_spinner").css("display", "inline");
$.ajax({ $.ajax({
url: "{{config('app.url') }}/api/v1/statuslabels/" + status_id + "/deployable", url: "{{config('app.label_url') }}/api/v1/statuslabels/" + status_id + "/deployable",
headers: { headers: {
"X-Requested-With": 'XMLHttpRequest', "X-Requested-With": 'XMLHttpRequest',
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content') "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')

View file

@ -112,7 +112,7 @@ $qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->label2_1d_type!=
@if ($settings->qr_code=='1') @if ($settings->qr_code=='1')
<div class="qr_img"> <div class="qr_img">
<img src="{{ config('app.url') }}/hardware/{{ $asset->id }}/qr_code" class="qr_img"> <img src="{{ config('app.label_url') }}/hardware/{{ $asset->id }}/qr_code" class="qr_img">
</div> </div>
@endif @endif
@ -158,7 +158,7 @@ $qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->label2_1d_type!=
@if ((($settings->alt_barcode_enabled=='1') && $settings->label2_1d_type!='')) @if ((($settings->alt_barcode_enabled=='1') && $settings->label2_1d_type!=''))
<div class="barcode_container"> <div class="barcode_container">
<img src="{{ config('app.url') }}/hardware/{{ $asset->id }}/barcode" class="barcode"> <img src="{{ config('app.label_url') }}/hardware/{{ $asset->id }}/barcode" class="barcode">
</div> </div>
@endif @endif

View file

@ -276,7 +276,7 @@
function genericRowLinkFormatter(destination) { function genericRowLinkFormatter(destination) {
return function (value,row) { return function (value,row) {
if (value) { if (value) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '">' + value + '</a>'; return '<a href="{{ config('app.label_url') }}/' + destination + '/' + row.id + '">' + value + '</a>';
} }
}; };
} }
@ -318,7 +318,7 @@
text_help = ''; text_help = '';
} }
return '<nobr><a href="{{ config('app.url') }}/' + destination + '/' + value.id + '" data-tooltip="true" title="'+ status_meta[value.status_meta] + '"> <i class="fa ' + icon_style + ' text-' + text_color + '"></i> ' + value.name + ' ' + text_help + ' </a> </nobr>'; return '<nobr><a href="{{ config('app.label_url') }}/' + destination + '/' + value.id + '" data-tooltip="true" title="'+ status_meta[value.status_meta] + '"> <i class="fa ' + icon_style + ' text-' + text_color + '"></i> ' + value.name + ' ' + text_help + ' </a> </nobr>';
} else if ((value) && (value.name)) { } else if ((value) && (value.name)) {
// Add some overrides for any funny urls we have // Add some overrides for any funny urls we have
@ -328,7 +328,7 @@
var dpolymorphicItemFormatterest = 'fields/'; var dpolymorphicItemFormatterest = 'fields/';
} }
return '<nobr><a href="{{ config('app.url') }}/' + dpolymorphicItemFormatterest + dest + '/' + value.id + '">' + value.name + '</a></span>'; return '<nobr><a href="{{ config('app.label_url') }}/' + dpolymorphicItemFormatterest + dest + '/' + value.id + '">' + value.name + '</a></span>';
} }
}; };
} }
@ -341,7 +341,7 @@
function hardwareAuditFormatter(value, row) { function hardwareAuditFormatter(value, row) {
return '<a href="{{ config('app.url') }}/hardware/' + row.id + '/audit" class="btn btn-sm bg-yellow" data-tooltip="true" title="Audit this item">{{ trans('general.audit') }}</a>'; return '<a href="{{ config('app.label_url') }}/hardware/' + row.id + '/audit" class="btn btn-sm bg-yellow" data-tooltip="true" title="Audit this item">{{ trans('general.audit') }}</a>';
} }

View file

@ -303,6 +303,7 @@
id="label2_2d_target" id="label2_2d_target"
:options="['hardware_id'=>'/hardware/{id} ('.trans('admin/settings/general.default').')', :options="['hardware_id'=>'/hardware/{id} ('.trans('admin/settings/general.default').')',
'ht_tag'=>'/ht/{asset_tag}', 'ht_tag'=>'/ht/{asset_tag}',
'custom_url_hardware_id'=>'/hardware/{id}',
'location' => '/location/{location_id}', 'location' => '/location/{location_id}',
]" ]"
:selected="old('label2_2d_target', $setting->label2_2d_target)" :selected="old('label2_2d_target', $setting->label2_2d_target)"

View file

@ -91,7 +91,7 @@
function statuslabelsAssetLinkFormatter(value, row) { function statuslabelsAssetLinkFormatter(value, row) {
if ((row) && (row.name)) { if ((row) && (row.name)) {
return '<a href="{{ config('app.url') }}/hardware/?status_id=' + row.id + '"> ' + row.name + '</a>'; return '<a href="{{ config('app.label_url') }}/hardware/?status_id=' + row.id + '"> ' + row.name + '</a>';
} }
} }