snipe-it/resources/views/partials/bootstrap-table.blade.php

856 lines
34 KiB
PHP
Raw Normal View History

@push('css')
<link rel="stylesheet" href="{{ url(mix('css/dist/bootstrap-table.css')) }}">
@endpush
2018-01-10 22:53:54 -08:00
@push('js')
<script src="{{ url(mix('js/dist/bootstrap-table.js')) }}"></script>
<script nonce="{{ csrf_token() }}">
2017-10-24 05:22:26 -07:00
$(function () {
var locale = '{{ config('app.locale') }}';
var blockedFields = "searchable,sortable,switchable,title,visible,formatter,class".split(",");
var keyBlocked = function(key) {
for(var j in blockedFields) {
if (key === blockedFields[j]) {
return true;
}
}
return false;
}
2017-10-24 05:22:26 -07:00
$('.snipe-table').bootstrapTable('destroy').each(function () {
data_export_options = $(this).attr('data-export-options');
export_options = data_export_options ? JSON.parse(data_export_options) : {};
export_options['htmlContent'] = false; // this is already the default; but let's be explicit about it
export_options['jspdf']= {"orientation": "l"};
// the following callback method is necessary to prevent XSS vulnerabilities
// (this is taken from Bootstrap Tables's default wrapper around jQuery Table Export)
export_options['onCellHtmlData'] = function (cell, rowIndex, colIndex, htmlData) {
if (cell.is('th')) {
return cell.find('.th-inner').text()
}
return htmlData
}
$(this).bootstrapTable({
classes: 'table table-responsive table-no-bordered',
2018-01-10 22:53:54 -08:00
ajaxOptions: {
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
},
// reorderableColumns: true,
stickyHeader: true,
stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10),
stickyHeaderOffsetRight: parseInt($('body').css('padding-right'), 10),
locale: locale,
undefinedText: '',
iconsPrefix: 'fa',
cookieStorage: '{{ config('session.bs_table_storage') }}',
cookie: true,
cookieExpire: '2y',
mobileResponsive: true,
maintainSelected: true,
trimOnSearch: false,
showSearchClearButton: true,
paginationFirstText: "{{ trans('general.first') }}",
paginationLastText: "{{ trans('general.last') }}",
paginationPreText: "{{ trans('general.previous') }}",
paginationNextText: "{{ trans('general.next') }}",
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',
queryParams: function (params) {
var newParams = {};
for(var i in params) {
if(!keyBlocked(i)) { // only send the field if it's not in blockedFields
newParams[i] = params[i];
}
}
return newParams;
},
formatLoadingMessage: function () {
return '<h2><i class="fas fa-spinner fa-spin" aria-hidden="true"></i> {{ trans('general.loading') }} </h4>';
},
icons: {
advancedSearchIcon: 'fas fa-search-plus',
paginationSwitchDown: 'fa-caret-square-o-down',
paginationSwitchUp: 'fa-caret-square-o-up',
fullscreen: 'fa-expand',
columns: 'fa-columns',
refresh: 'fas fa-sync-alt',
export: 'fa-download',
clearSearch: 'fa-times'
},
exportOptions: export_options,
exportTypes: ['xlsx', 'excel', 'csv', 'pdf','json', 'xml', 'txt', 'sql', 'doc' ],
onLoadSuccess: function () {
$('[data-tooltip="true"]').tooltip(); // Needed to attach tooltips after ajax call
}
});
});
});
2018-01-10 22:53:54 -08:00
2017-03-11 04:26:01 -08:00
2017-10-24 05:22:26 -07:00
2017-01-18 19:28:35 -08:00
2017-08-25 18:40:20 -07:00
function dateRowCheckStyle(value) {
if ((value.days_to_next_audit) && (value.days_to_next_audit < {{ $snipeSettings->audit_warning_days ?: 0 }})) {
2017-08-25 18:40:20 -07:00
return { classes : "danger" }
}
return {};
}
// These methods dynamically add/remove hidden input values in the bulk actions form
$('.snipe-table').on('check.bs.table .btSelectItem', function (row, $element) {
var buttonName = $(this).data('bulk-button-id');
var tableId = $(this).data('id-table');
$(buttonName).removeAttr('disabled');
$(buttonName).after('<input id="' + tableId + '_checkbox_' + $element.id + '" type="hidden" name="ids[]" value="' + $element.id + '">');
2017-01-18 19:28:35 -08:00
});
$('.snipe-table').on('check-all.bs.table', function (event, rowsAfter) {
var buttonName = $(this).data('bulk-button-id');
$(buttonName).removeAttr('disabled');
var tableId = $(this).data('id-table');
for (var i in rowsAfter) {
// Do not select things that were already selected
if($('#'+ tableId + '_checkbox_' + rowsAfter[i].id).length == 0) {
$(buttonName).after('<input id="' + tableId + '_checkbox_' + rowsAfter[i].id + '" type="hidden" name="ids[]" value="' + rowsAfter[i].id + '">');
}
}
});
$('.snipe-table').on('uncheck.bs.table .btSelectItem', function (row, $element) {
var tableId = $(this).data('id-table');
$( "#" + tableId + "_checkbox_" + $element.id).remove();
});
// Handle whether or not the edit button should be disabled
2017-01-18 19:28:35 -08:00
$('.snipe-table').on('uncheck.bs.table', function () {
var buttonName = $(this).data('bulk-button-id');
if ($(this).bootstrapTable('getSelections').length == 0) {
$(buttonName).attr('disabled', 'disabled');
2017-01-18 19:28:35 -08:00
}
});
$('.snipe-table').on('uncheck-all.bs.table', function (event, rowsAfter, rowsBefore) {
var buttonName = $(this).data('bulk-button-id');
$(buttonName).attr('disabled', 'disabled');
var tableId = $(this).data('id-table');
for (var i in rowsBefore) {
$('#' + tableId + "_checkbox_" + rowsBefore[i].id).remove();
}
2017-01-18 19:28:35 -08:00
});
// This only works for model index pages because it uses the row's model ID
function genericRowLinkFormatter(destination) {
return function (value,row) {
if (value) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '">' + value + '</a>';
}
};
2017-01-18 19:28:35 -08:00
}
// Use this when we're introspecting into a column object and need to link
function genericColumnObjLinkFormatter(destination) {
return function (value,row) {
if ((value) && (value.status_meta)) {
2017-09-29 15:24:33 -07:00
var text_color;
var icon_style;
var text_help;
var status_meta = {
'deployed': '{{ strtolower(trans('general.deployed')) }}',
'deployable': '{{ strtolower(trans('admin/hardware/general.deployable')) }}',
'archived': '{{ strtolower(trans('general.archived')) }}',
'pending': '{{ strtolower(trans('general.pending')) }}'
}
2017-09-29 15:24:33 -07:00
switch (value.status_meta) {
case 'deployed':
2017-09-29 15:24:33 -07:00
text_color = 'blue';
icon_style = 'fa-circle';
text_help = '<label class="label label-default">{{ trans('general.deployed') }}</label>';
2017-09-29 15:24:33 -07:00
break;
case 'deployable':
2017-09-29 15:24:33 -07:00
text_color = 'green';
icon_style = 'fa-circle';
text_help = '';
2017-09-29 15:24:33 -07:00
break;
case 'pending':
2017-09-29 15:24:33 -07:00
text_color = 'orange';
icon_style = 'fa-circle';
text_help = '';
2017-09-29 15:24:33 -07:00
break;
default:
text_color = 'red';
icon_style = 'fa-times';
text_help = '';
2017-09-29 15:24:33 -07:00
}
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>';
2017-09-28 21:18:00 -07:00
} else if ((value) && (value.name)) {
// Add some overrides for any funny urls we have
var dest = destination;
var dpolymorphicItemFormatterest = '';
if (destination=='fieldsets') {
var dpolymorphicItemFormatterest = 'fields/';
}
return '<nobr><a href="{{ config('app.url') }}/' + dpolymorphicItemFormatterest + dest + '/' + value.id + '">' + value.name + '</a></span>';
}
};
2017-01-18 19:28:35 -08:00
}
function hardwareAuditFormatter(value, row) {
return '<a href="{{ config('app.url') }}/hardware/audit/' + row.id + '/" class="btn btn-sm bg-yellow" data-tooltip="true" title="Audit this item">{{ trans('general.audit') }}</a>';
}
2017-01-24 22:25:17 -08:00
// Make the edit/delete buttons
function genericActionsFormatter(owner_name, element_name) {
if (!element_name) {
element_name = '';
}
return function (value,row) {
var actions = '<nobr>';
// Add some overrides for any funny urls we have
2018-10-31 06:06:38 -07:00
var dest = owner_name;
2018-10-31 06:06:38 -07:00
if (dest =='groups') {
var dest = 'admin/groups';
}
2018-10-31 06:06:38 -07:00
if (dest =='maintenances') {
var dest = 'hardware/maintenances';
}
2018-10-31 06:06:38 -07:00
if(element_name != '') {
dest = dest + '/' + row.owner_id + '/' + element_name;
2018-10-19 07:30:25 -07:00
}
if ((row.available_actions) && (row.available_actions.clone === true)) {
2023-05-01 16:27:21 -07:00
actions += '<a href="{{ config('app.url') }}/' + dest + '/' + row.id + '/clone" class="actions btn btn-sm btn-info" data-tooltip="true" title="{{ trans('general.clone_item') }}"><i class="far fa-clone" aria-hidden="true"></i><span class="sr-only">Clone</span></a>&nbsp;';
}
if ((row.available_actions) && (row.available_actions.update === true)) {
2023-05-01 16:27:21 -07:00
actions += '<a href="{{ config('app.url') }}/' + dest + '/' + row.id + '/edit" class="actions btn btn-sm btn-warning" data-tooltip="true" title="{{ trans('general.update') }}"><i class="fas fa-pencil-alt" aria-hidden="true"></i><span class="sr-only">{{ trans('general.update') }}</span></a>&nbsp;';
}
if ((row.available_actions) && (row.available_actions.delete === true)) {
// use the asset tag if no name is provided
var name_for_box = row.name
if (row.name=='') {
var name_for_box = row.asset_tag
}
actions += '<a href="{{ config('app.url') }}/' + dest + '/' + row.id + '" '
2023-05-01 16:27:21 -07:00
+ ' class="actions btn btn-danger btn-sm delete-asset" data-tooltip="true" '
2017-02-15 23:04:49 -08:00
+ ' data-toggle="modal" '
+ ' data-content="{{ trans('general.sure_to_delete') }} ' + name_for_box + '?" '
2017-07-08 13:36:25 -07:00
+ ' data-title="{{ trans('general.delete') }}" onClick="return false;">'
+ '<i class="fas fa-trash" aria-hidden="true"></i><span class="sr-only">{{ trans('general.delete') }}</span></a>&nbsp;';
} else {
// Do not show the delete button on things that are already deleted
if ((row.available_actions) && (row.available_actions.restore != true)) {
actions += '<span data-tooltip="true" title="{{ trans('general.cannot_be_deleted') }}"><a class="btn btn-danger btn-sm delete-asset disabled" onClick="return false;"><i class="fas fa-trash"></i></a></span>&nbsp;';
}
}
2017-09-06 17:11:43 -07:00
if ((row.available_actions) && (row.available_actions.restore === true)) {
actions += '<form style="display: inline;" method="POST" action="{{ config('app.url') }}/' + dest + '/' + row.id + '/restore"> ';
actions += '@csrf';
actions += '<button class="btn btn-sm btn-warning" data-tooltip="true" title="{{ trans('general.restore') }}"><i class="fas fa-retweet"></i></button>&nbsp;';
2017-09-06 17:11:43 -07:00
}
actions +='</nobr>';
return actions;
};
2017-01-18 19:28:35 -08:00
}
// This handles the icons and display of polymorphic entries
function polymorphicItemFormatter(value) {
var item_destination = '';
var item_icon;
if ((value) && (value.type)) {
if (value.type == 'asset') {
item_destination = 'hardware';
item_icon = 'fas fa-barcode';
} else if (value.type == 'accessory') {
item_destination = 'accessories';
item_icon = 'far fa-keyboard';
} else if (value.type == 'component') {
item_destination = 'components';
item_icon = 'far fa-hdd';
} else if (value.type == 'consumable') {
item_destination = 'consumables';
item_icon = 'fas fa-tint';
} else if (value.type == 'license') {
item_destination = 'licenses';
item_icon = 'far fa-save';
} else if (value.type == 'user') {
item_destination = 'users';
item_icon = 'fas fa-user';
} else if (value.type == 'location') {
item_destination = 'locations'
item_icon = 'fas fa-map-marker-alt';
} else if (value.type == 'model') {
item_destination = 'models'
item_icon = '';
}
// display the username if it's checked out to a user, but don't do it if the username's there already
if (value.username && !value.name.match('\\(') && !value.name.match('\\)')) {
value.name = value.name + ' (' + value.username + ')';
}
return '<nobr><a href="{{ config('app.url') }}/' + item_destination +'/' + value.id + '" data-tooltip="true" title="' + value.type + '"><i class="' + item_icon + ' text-{{ $snipeSettings->skin!='' ? $snipeSettings->skin : 'blue' }} "></i> ' + value.name + '</a></nobr>';
} else {
2017-05-23 15:06:43 -07:00
return '';
}
}
// This just prints out the item type in the activity report
function itemTypeFormatter(value, row) {
if ((row) && (row.item) && (row.item.type)) {
return row.item.type;
}
}
// Convert line breaks to <br>
function notesFormatter(value) {
if (value) {
return value.replace(/(?:\r\n|\r|\n)/g, '<br />');;
}
}
// We need a special formatter for license seats, since they don't work exactly the same
// Checkouts need the license ID, checkins need the specific seat ID
function licenseSeatInOutFormatter(value, row) {
// The user is allowed to check the license seat out and it's available
if ((row.available_actions.checkout == true) && (row.user_can_checkout == true) && ((!row.asset_id) && (!row.assigned_to))) {
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
} else {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check in this license seat.">{{ trans('general.checkin') }}</a>';
}
}
2017-01-24 22:25:17 -08:00
function genericCheckinCheckoutFormatter(destination) {
return function (value,row) {
// The user is allowed to check items out, AND the item is deployable
if ((row.available_actions.checkout == true) && (row.user_can_checkout == true) && ((!row.asset_id) && (!row.assigned_to))) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '/checkout" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
// The user is allowed to check items out, but the item is not able to be checked out
} else if (((row.user_can_checkout == false)) && (row.available_actions.checkout == true) && (!row.assigned_to)) {
// We use slightly different language for assets versus other things, since they are the only
// item that has a status label
if (destination =='hardware') {
return '<span data-tooltip="true" title="{{ trans('admin/hardware/general.undeployable_tooltip') }}"><a class="btn btn-sm bg-maroon disabled">{{ trans('general.checkout') }}</a></span>';
} else {
return '<span data-tooltip="true" title="{{ trans('general.undeployable_tooltip') }}"><a class="btn btn-sm bg-maroon disabled">{{ trans('general.checkout') }}</a></span>';
}
// The user is allowed to check items in
2017-09-28 21:18:00 -07:00
} else if (row.available_actions.checkin == true) {
if (row.assigned_to) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
2017-09-28 21:18:00 -07:00
} else if (row.assigned_pivot_id) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.assigned_pivot_id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
2017-09-28 21:18:00 -07:00
}
}
}
}
WIP - Improved requested assets (#5289) * WIP - beginning of improved requested assets - Use Ajax tables for faster loading - Use new notifications for requesting an asset TODO: - Use ajax tables for requestable asset models - Use new notifications for canceling an asset request - Expire requests once the asset has been checked out to the requesting user * Only show asset name in email if it has one * Refactor requested method to only include non-canceled requests * Refactored requestable assets to log request and cancelation * Added softdeletes on checkout requests * Differentiate between canceling and deleting requests * Added asset request cancelation notification * Added timestamps and corrected unique key on requests table * Improved requests view * Re-use blade for cancel/request email * Refactored BS table formatter for requested assets * Location name min reduced to 2 * Added PAT test as maintenance option This needs to be refactored into database-driven options with a UI * Better slack message * Added getImageUrl method for assets * Include qty in request notifications TODO: - Try to pull requested info from original request for cancelation, otherwise it will default to 1 * Removed old asset request/cancel emails * Added user profile asset request routes * Added profile controller requested assets method * Added blade link to requested assets for profile view * Sort user history desc * Added requested assets blade * Added canceled at to checkoutRequest method * Include qty in request * Fixed comment, removed allowed_columns * Removed Queable methods, since we don’t use a queue * Fixed return type in method doc * Fixed version number * Changed id to user_id for clarity
2018-04-04 17:33:02 -07:00
// This is only used by the requestable assets section
function assetRequestActionsFormatter (row, value) {
if (value.assigned_to_self == true){
return '<button class="btn btn-danger btn-sm disabled" data-tooltip="true" title="Cancel this item request">{{ trans('button.cancel') }}</button>';
} else if (value.available_actions.cancel == true) {
return '<form action="{{ config('app.url') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-danger btn-sm" data-tooltip="true" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
WIP - Improved requested assets (#5289) * WIP - beginning of improved requested assets - Use Ajax tables for faster loading - Use new notifications for requesting an asset TODO: - Use ajax tables for requestable asset models - Use new notifications for canceling an asset request - Expire requests once the asset has been checked out to the requesting user * Only show asset name in email if it has one * Refactor requested method to only include non-canceled requests * Refactored requestable assets to log request and cancelation * Added softdeletes on checkout requests * Differentiate between canceling and deleting requests * Added asset request cancelation notification * Added timestamps and corrected unique key on requests table * Improved requests view * Re-use blade for cancel/request email * Refactored BS table formatter for requested assets * Location name min reduced to 2 * Added PAT test as maintenance option This needs to be refactored into database-driven options with a UI * Better slack message * Added getImageUrl method for assets * Include qty in request notifications TODO: - Try to pull requested info from original request for cancelation, otherwise it will default to 1 * Removed old asset request/cancel emails * Added user profile asset request routes * Added profile controller requested assets method * Added blade link to requested assets for profile view * Sort user history desc * Added requested assets blade * Added canceled at to checkoutRequest method * Include qty in request * Fixed comment, removed allowed_columns * Removed Queable methods, since we don’t use a queue * Fixed return type in method doc * Fixed version number * Changed id to user_id for clarity
2018-04-04 17:33:02 -07:00
} else if (value.available_actions.request == true) {
return '<form action="{{ config('app.url') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-primary btn-sm" data-tooltip="true" title="Request this item">{{ trans('button.request') }}</button></form>';
WIP - Improved requested assets (#5289) * WIP - beginning of improved requested assets - Use Ajax tables for faster loading - Use new notifications for requesting an asset TODO: - Use ajax tables for requestable asset models - Use new notifications for canceling an asset request - Expire requests once the asset has been checked out to the requesting user * Only show asset name in email if it has one * Refactor requested method to only include non-canceled requests * Refactored requestable assets to log request and cancelation * Added softdeletes on checkout requests * Differentiate between canceling and deleting requests * Added asset request cancelation notification * Added timestamps and corrected unique key on requests table * Improved requests view * Re-use blade for cancel/request email * Refactored BS table formatter for requested assets * Location name min reduced to 2 * Added PAT test as maintenance option This needs to be refactored into database-driven options with a UI * Better slack message * Added getImageUrl method for assets * Include qty in request notifications TODO: - Try to pull requested info from original request for cancelation, otherwise it will default to 1 * Removed old asset request/cancel emails * Added user profile asset request routes * Added profile controller requested assets method * Added blade link to requested assets for profile view * Sort user history desc * Added requested assets blade * Added canceled at to checkoutRequest method * Include qty in request * Fixed comment, removed allowed_columns * Removed Queable methods, since we don’t use a queue * Fixed return type in method doc * Fixed version number * Changed id to user_id for clarity
2018-04-04 17:33:02 -07:00
}
}
2017-01-24 22:25:17 -08:00
var formatters = [
'hardware',
'accessories',
2017-01-26 18:46:18 -08:00
'consumables',
'components',
2017-01-24 22:25:17 -08:00
'locations',
'users',
'manufacturers',
'maintenances',
2017-01-24 22:25:17 -08:00
'statuslabels',
'models',
'licenses',
'categories',
'suppliers',
'departments',
2017-01-24 22:25:17 -08:00
'companies',
'depreciations',
'fieldsets',
2018-10-19 07:30:25 -07:00
'groups',
2018-10-31 06:06:38 -07:00
'kits'
2017-01-24 22:25:17 -08:00
];
2017-01-18 19:46:43 -08:00
for (var i in formatters) {
window[formatters[i] + 'LinkFormatter'] = genericRowLinkFormatter(formatters[i]);
window[formatters[i] + 'LinkObjFormatter'] = genericColumnObjLinkFormatter(formatters[i]);
window[formatters[i] + 'ActionsFormatter'] = genericActionsFormatter(formatters[i]);
window[formatters[i] + 'InOutFormatter'] = genericCheckinCheckoutFormatter(formatters[i]);
2017-01-18 19:46:43 -08:00
}
2018-10-31 06:06:38 -07:00
var child_formatters = [
2018-10-19 07:30:25 -07:00
['kits', 'models'],
['kits', 'licenses'],
['kits', 'consumables'],
['kits', 'accessories'],
2018-10-19 07:30:25 -07:00
];
2018-10-31 06:06:38 -07:00
for (var i in child_formatters) {
var owner_name = child_formatters[i][0];
var child_name = child_formatters[i][1];
window[owner_name + '_' + child_name + 'ActionsFormatter'] = genericActionsFormatter(owner_name, child_name);
2018-10-19 07:30:25 -07:00
}
// This is gross, but necessary so that we can package the API response
// for custom fields in a more useful way.
function customFieldsFormatter(value, row) {
if ((!this) || (!this.title)) {
return '';
}
var field_column = this.title;
// Pull out any HTMl that might be passed via the presenter
// (for example, the locked icon for encrypted fields)
var field_column_plain = field_column.replace(/<(?:.|\n)*?> ?/gm, '');
if ((row.custom_fields) && (row.custom_fields[field_column_plain])) {
// If the field type needs special formatting, do that here
if ((row.custom_fields[field_column_plain].field_format) && (row.custom_fields[field_column_plain].value)) {
if (row.custom_fields[field_column_plain].field_format=='URL') {
return '<a href="' + row.custom_fields[field_column_plain].value + '" target="_blank" rel="noopener">' + row.custom_fields[field_column_plain].value + '</a>';
} else if (row.custom_fields[field_column_plain].field_format=='BOOLEAN') {
return (row.custom_fields[field_column_plain].value == 1) ? "<span class='fas fa-check-circle' style='color:green' />" : "<span class='fas fa-times-circle' style='color:red' />";
} else if (row.custom_fields[field_column_plain].field_format=='EMAIL') {
return '<a href="mailto:' + row.custom_fields[field_column_plain].value + '">' + row.custom_fields[field_column_plain].value + '</a>';
}
}
return row.custom_fields[field_column_plain].value;
}
}
function createdAtFormatter(value) {
if ((value) && (value.formatted)) {
return value.formatted;
}
}
function externalLinkFormatter(value) {
if (value) {
if ((value.indexOf("{") === -1) || (value.indexOf("}") ===-1)) {
return '<nobr><a href="' + value + '" target="_blank" title="External link to ' + value + '" data-tooltip="true" ><i class="fa fa-external-link"></i> ' + value + '</a></nobr>';
}
return value;
}
}
2017-10-17 21:43:57 -07:00
function groupsFormatter(value) {
if (value) {
var groups = '';
for (var index in value.rows) {
groups += '<a href="{{ config('app.url') }}/admin/groups/' + value.rows[index].id + '" class="label label-default">' + value.rows[index].name + '</a> ';
2017-10-17 21:43:57 -07:00
}
return groups;
}
}
function changeLogFormatter(value) {
var result = '';
var pretty_index = '';
for (var index in value) {
// Check if it's a custom field
if (index.startsWith('_snipeit_')) {
pretty_index = index.replace("_snipeit_", "Custom:_");
} else {
pretty_index = index;
}
extra_pretty_index = prettyLog(pretty_index);
result += extra_pretty_index + ': <del>' + value[index].old + '</del> <i class="fas fa-long-arrow-alt-right" aria-hidden="true"></i> ' + value[index].new + '<br>'
}
return result;
}
function prettyLog(str) {
let frags = str.split('_');
for (let i = 0; i < frags.length; i++) {
frags[i] = frags[i].charAt(0).toUpperCase() + frags[i].slice(1);
}
return frags.join(' ');
}
2018-01-20 00:20:45 -08:00
// Create a linked phone number in the table list
function phoneFormatter(value) {
if (value) {
return '<a href="tel:' + value + '">' + value + '</a>';
}
}
function deployedLocationFormatter(row, value) {
if ((row) && (row!=undefined)) {
return '<a href="{{ config('app.url') }}/locations/' + row.id + '">' + row.name + '</a>';
} else if (value.rtd_location) {
return '<a href="{{ config('app.url') }}/locations/' + value.rtd_location.id + '" data-tooltip="true" title="Default Location">' + value.rtd_location.name + '</a>';
}
}
2017-10-17 21:43:57 -07:00
function groupsAdminLinkFormatter(value, row) {
return '<a href="{{ config('app.url') }}/admin/groups/' + row.id + '">' + value + '</a>';
2017-10-17 21:43:57 -07:00
}
function assetTagLinkFormatter(value, row) {
if ((row.asset) && (row.asset.id)) {
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.asset_tag + '</a>';
}
return '';
}
function departmentNameLinkFormatter(value, row) {
if ((row.assigned_user) && (row.assigned_user.department) && (row.assigned_user.department.name)) {
2024-01-04 12:36:57 -08:00
return '<a href="{{ config('app.url') }}/department/' + row.assigned_user.department.id + '">' + row.assigned_user.department.name + '</a>';
}
}
function assetNameLinkFormatter(value, row) {
if ((row.asset) && (row.asset.name)) {
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.name + '</a>';
}
}
function trueFalseFormatter(value) {
if ((value) && ((value == 'true') || (value == '1'))) {
return '<i class="fas fa-check text-success"></i><span class="sr-only">{{ trans('general.true') }}</span>';
} else {
return '<i class="fas fa-times text-danger"></i><span class="sr-only">{{ trans('general.false') }}</span>';
2017-01-18 19:28:35 -08:00
}
}
function dateDisplayFormatter(value) {
if (value) {
return value.formatted;
}
}
function iconFormatter(value) {
if (value) {
return '<i class="' + value + ' icon-med"></i>';
}
}
2017-01-18 19:28:35 -08:00
function emailFormatter(value) {
2017-01-18 19:28:35 -08:00
if (value) {
2021-11-22 08:58:26 -08:00
return '<a href="mailto:' + value + '">' + value + '</a>';
2017-01-18 19:28:35 -08:00
}
}
function linkFormatter(value) {
if (value) {
2021-11-22 08:58:26 -08:00
return '<a href="' + value + '">' + value + '</a>';
}
}
function assetCompanyFilterFormatter(value, row) {
if (value) {
return '<a href="{{ config('app.url') }}/hardware/?company_id=' + row.id + '">' + value + '</a>';
}
}
function assetCompanyObjFilterFormatter(value, row) {
if ((row) && (row.company)) {
return '<a href="{{ config('app.url') }}/hardware/?company_id=' + row.company.id + '">' + row.company.name + '</a>';
}
}
function usersCompanyObjFilterFormatter(value, row) {
if (value) {
return '<a href="{{ config('app.url') }}/users/?company_id=' + row.id + '">' + value + '</a>';
} else {
return value;
}
}
function employeeNumFormatter(value, row) {
if ((row) && (row.assigned_to) && ((row.assigned_to.employee_number))) {
return '<a href="{{ config('app.url') }}/users/' + row.assigned_to.id + '">' + row.assigned_to.employee_number + '</a>';
}
}
function orderNumberObjFilterFormatter(value, row) {
if (value) {
return '<a href="{{ config('app.url') }}/hardware/?order_number=' + row.order_number + '">' + row.order_number + '</a>';
}
}
2023-06-12 12:10:19 -07:00
function auditImageFormatter(value){
if (value){
return '<a href="' + value.url + '" data-toggle="lightbox" data-type="image"><img src="' + value.url + '" style="max-height: {{ $snipeSettings->thumbnail_max_h }}px; width: auto;" class="img-responsive"></a>'
}
}
2023-06-12 12:10:19 -07:00
function imageFormatter(value, row) {
if (value) {
// This is a clunky override to handle unusual API responses where we're presenting a link instead of an array
if (row.avatar) {
var altName = '';
}
else if (row.name) {
var altName = row.name;
}
else if ((row) && (row.model)) {
var altName = row.model.name;
}
return '<a href="' + value + '" data-toggle="lightbox" data-type="image"><img src="' + value + '" style="max-height: {{ $snipeSettings->thumbnail_max_h }}px; width: auto;" class="img-responsive" alt="' + altName + '"></a>';
}
}
function downloadFormatter(value) {
if (value) {
return '<a href="' + value + '" target="_blank"><i class="fas fa-download"></i></a>';
}
}
2018-05-02 14:13:06 -07:00
function fileUploadFormatter(value) {
if ((value) && (value.url) && (value.inlineable)) {
return '<a href="' + value.url + '" data-toggle="lightbox" data-type="image"><img src="' + value.url + '" style="max-height: {{ $snipeSettings->thumbnail_max_h }}px; width: auto;" class="img-responsive"></a>';
} else if ((value) && (value.url)) {
return '<a href="' + value.url + '" class="btn btn-default"><i class="fas fa-download"></i></a>';
2018-05-02 14:13:06 -07:00
}
}
function fileUploadNameFormatter(value) {
console.dir(value);
if ((value) && (value.filename) && (value.url)) {
return '<a href="' + value.url + '">' + value.filename + '</a>';
}
}
2022-11-01 05:00:53 -07:00
function labelPerPageFormatter(value, row, index, field) {
if (row) {
2022-11-01 18:51:02 -07:00
if (!row.hasOwnProperty('sheet_info')) { return 1; }
2022-11-01 05:00:53 -07:00
else { return row.sheet_info.labels_per_page; }
}
}
function labelRadioFormatter(value, row, index, field) {
if (row) {
return row.name == '{{ str_replace("\\", "\\\\", $snipeSettings->label2_template) }}';
}
}
function labelSizeFormatter(value, row) {
if (row) {
return row.width + ' x ' + row.height + ' ' + row.unit;
}
}
function cleanFloat(number) {
if(!number) { // in a JavaScript context, meaning, if it's null or zero or unset
return 0.0;
}
if ("{{$snipeSettings->digit_separator}}" == "1.234,56") {
// yank periods, change commas to periods
periodless = number.toString().replace(/\./g,"");
decimalfixed = periodless.replace(/,/g,".");
} else {
// yank commas, that's it.
decimalfixed = number.toString().replace(/\,/g,"");
}
return parseFloat(decimalfixed);
}
function sumFormatter(data) {
if (Array.isArray(data)) {
var field = this.field;
var total_sum = data.reduce(function(sum, row) {
return (sum) + (cleanFloat(row[field]) || 0);
}, 0);
return numberWithCommas(total_sum.toFixed(2));
}
return 'not an array';
}
function sumFormatterQuantity(data){
if(Array.isArray(data)) {
// Prevents issues on page load where data is an empty array
if(data[0] == undefined){
return 0.00
}
// Check that we are actually trying to sum cost from a table
// that has a quantity column. We must perform this check to
// support licences which use seats instead of qty
if('qty' in data[0]) {
var multiplier = 'qty';
} else if('seats' in data[0]) {
var multiplier = 'seats';
} else {
return 'no quantity';
}
var total_sum = data.reduce(function(sum, row) {
return (sum) + (cleanFloat(row["purchase_cost"])*row[multiplier] || 0);
}, 0);
return numberWithCommas(total_sum.toFixed(2));
}
return 'not an array';
}
function numberWithCommas(value) {
if ((value) && ("{{$snipeSettings->digit_separator}}" == "1.234,56")){
var parts = value.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
return parts.join(",");
} else {
var parts = value.toString().split(",");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
return value
}
2017-01-18 19:28:35 -08:00
$(function () {
$('#bulkEdit').click(function () {
var selectedIds = $('.snipe-table').bootstrapTable('getSelections');
$.each(selectedIds, function(key,value) {
$( "#bulkForm" ).append($('<input type="hidden" name="ids[' + value.id + ']" value="' + value.id + '">' ));
});
});
});
$(function() {
// This handles the search box highlighting on both ajax and client-side
// bootstrap tables
var searchboxHighlighter = function (event) {
$('.search-input').each(function (index, element) {
if ($(element).val() != '') {
$(element).addClass('search-highlight');
$(element).next().children().addClass('search-highlight');
} else {
$(element).removeClass('search-highlight');
$(element).next().children().removeClass('search-highlight');
}
});
};
$('.search button[name=clearSearch]').click(searchboxHighlighter);
searchboxHighlighter({ name:'pageload'});
$('.search-input').keyup(searchboxHighlighter);
// This is necessary to make the bootstrap tooltips work inside of the
// wenzhixin/bootstrap-table formatters
$('#table').on('post-body.bs.table', function () {
$('[data-tooltip="true"]').tooltip({
container: 'body'
});
});
});
</script>
@endpush