Merge pull request #15689 from snipe/better_handle_inline_files

Better handle inline files in file listing
This commit is contained in:
snipe 2024-10-22 16:26:48 +01:00 committed by GitHub
commit 252d99421c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 329 additions and 949 deletions

View file

@ -1123,6 +1123,7 @@ class Helper
'png' => 'far fa-image', 'png' => 'far fa-image',
'webp' => 'far fa-image', 'webp' => 'far fa-image',
'avif' => 'far fa-image', 'avif' => 'far fa-image',
'svg' => 'fas fa-vector-square',
// word // word
'doc' => 'far fa-file-word', 'doc' => 'far fa-file-word',
'docx' => 'far fa-file-word', 'docx' => 'far fa-file-word',
@ -1135,7 +1136,7 @@ class Helper
//Text //Text
'txt' => 'far fa-file-alt', 'txt' => 'far fa-file-alt',
'rtf' => 'far fa-file-alt', 'rtf' => 'far fa-file-alt',
'xml' => 'far fa-file-alt', 'xml' => 'fas fa-code',
// Misc // Misc
'pdf' => 'far fa-file-pdf', 'pdf' => 'far fa-file-pdf',
'lic' => 'far fa-save', 'lic' => 'far fa-save',
@ -1148,41 +1149,7 @@ class Helper
return 'far fa-file'; return 'far fa-file';
} }
public static function show_file_inline($filename)
{
$extension = substr(strrchr($filename, '.'), 1);
if ($extension) {
switch ($extension) {
case 'jpg':
case 'jpeg':
case 'gif':
case 'png':
case 'webp':
case 'avif':
return true;
break;
default:
return false;
}
}
return false;
}
/**
* Generate a random encrypted password.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @return string
*/
public static function generateEncyrptedPassword(): string
{
return bcrypt(self::generateUnencryptedPassword());
}
/** /**
* Get a random unencrypted password. * Get a random unencrypted password.

View file

@ -7,6 +7,7 @@ use Illuminate\Http\Response;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
class StorageHelper class StorageHelper
{ {
public static function downloader($filename, $disk = 'default') : BinaryFileResponse | RedirectResponse | StreamedResponse public static function downloader($filename, $disk = 'default') : BinaryFileResponse | RedirectResponse | StreamedResponse
@ -25,4 +26,64 @@ class StorageHelper
return Storage::disk($disk)->download($filename); return Storage::disk($disk)->download($filename);
} }
} }
/**
* This determines the file types that should be allowed inline and checks their fileinfo extension
* to determine that they are safe to display inline.
*
* @author <A. Gianotto> [<snipe@snipe.net]>
* @since v7.0.14
* @param $file_with_path
* @return bool
*/
public static function allowSafeInline($file_with_path) {
$allowed_inline = [
'pdf',
'svg',
'jpg',
'gif',
'svg',
'avif',
'webp',
'png',
];
// The file exists and is allowed to be displayed inline
if (Storage::exists($file_with_path) && (in_array(pathinfo($file_with_path, PATHINFO_EXTENSION), $allowed_inline))) {
return true;
}
return false;
}
/**
* Decide whether to show the file inline or download it.
*/
public static function showOrDownloadFile($file, $filename) {
$headers = [];
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
// This is NOT allowed as inline - force it to be displayed as text in the browser
if (self::allowSafeInline($file) != true) {
$headers = array_merge($headers, ['Content-Type' => 'text/plain']);
}
}
// Everything else seems okay, but the file doesn't exist on the server.
if (Storage::missing($file)) {
throw new FileNotFoundException();
}
return Storage::download($file, $filename, $headers);
}
} }

View file

@ -106,50 +106,29 @@ class AccessoriesFilesController extends Controller
* @param int $accessoryId * @param int $accessoryId
* @param int $fileId * @param int $fileId
*/ */
public function show($accessoryId = null, $fileId = null, $download = true) : View | RedirectResponse | Response | BinaryFileResponse | StreamedResponse public function show($accessoryId = null, $fileId = null) : View | RedirectResponse | Response | BinaryFileResponse | StreamedResponse
{ {
Log::debug('Private filesystem is: '.config('filesystems.default'));
$accessory = Accessory::find($accessoryId);
// the accessory is valid // the accessory is valid
if (isset($accessory->id)) { if ($accessory = Accessory::find($accessoryId)) {
$this->authorize('view', $accessory); $this->authorize('view', $accessory);
$this->authorize('accessories.files', $accessory); $this->authorize('accessories.files', $accessory);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $accessory->id)->find($fileId)) { if ($log = Actionlog::whereNotNull('filename')->where('item_id', $accessory->id)->find($fileId)) {
return redirect()->route('accessories.index')->with('error', trans('admin/users/message.log_record_not_found'));
}
$file = 'private_uploads/accessories/'.$log->filename; $file = 'private_uploads/accessories/'.$log->filename;
if (Storage::missing($file)) { try {
Log::debug('FILE DOES NOT EXISTS for '.$file); return StorageHelper::showOrDownloadFile($file, $log->filename);
Log::debug('URL should be '.Storage::url($file)); } catch (\Exception $e) {
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.file_not_found'));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
// won't work, as they're not accessible via the web
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
} }
} }
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.log_record_not_found'));
} }
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId])); return redirect()->route('accessories.index')->with('error', trans('general.file_not_found'));
} }
} }

View file

@ -61,43 +61,30 @@ class AssetFilesController extends Controller
*/ */
public function show($assetId = null, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse public function show($assetId = null, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse
{ {
$asset = Asset::find($assetId); if ($asset = Asset::find($assetId)) {
// the asset is valid
if (isset($asset->id)) {
$this->authorize('view', $asset); $this->authorize('view', $asset);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) { if ($log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
$file = 'private_uploads/assets/'.$log->filename; $file = 'private_uploads/assets/'.$log->filename;
if ($log->action_type == 'audit') { if ($log->action_type == 'audit') {
$file = 'private_uploads/audits/'.$log->filename; $file = 'private_uploads/audits/'.$log->filename;
} }
if (! Storage::exists($file)) { try {
return response('File '.$file.' not found on server', 404) return StorageHelper::showOrDownloadFile($file, $log->filename);
->header('Content-Type', 'text/plain'); } catch (\Exception $e) {
return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.file_not_found'));
} }
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
} }
return StorageHelper::downloader($file); return redirect()->route('hardware.show', ['hardware' => $asset])->with('error', trans('general.log_record_not_found'));
} }
// Prepare the error message
$error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]);
// Redirect to the hardware management page return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
return redirect()->route('hardware.index')->with('error', $error);
} }
/** /**

View file

@ -17,7 +17,6 @@ use App\Models\Location;
use App\Models\Setting; use App\Models\Setting;
use App\Models\Statuslabel; use App\Models\Statuslabel;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\View\Label; use App\View\Label;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;

View file

@ -112,40 +112,25 @@ class ComponentsFilesController extends Controller
public function show($componentId = null, $fileId = null) public function show($componentId = null, $fileId = null)
{ {
Log::debug('Private filesystem is: '.config('filesystems.default')); Log::debug('Private filesystem is: '.config('filesystems.default'));
$component = Component::find($componentId);
// the component is valid // the component is valid
if (isset($component->id)) { if ($component = Component::find($componentId)) {
$this->authorize('view', $component); $this->authorize('view', $component);
$this->authorize('components.files', $component); $this->authorize('components.files', $component);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $component->id)->find($fileId)) { if ($log = Actionlog::whereNotNull('filename')->where('item_id', $component->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
$file = 'private_uploads/components/'.$log->filename; $file = 'private_uploads/components/'.$log->filename;
if (Storage::missing($file)) { try {
Log::debug('FILE DOES NOT EXISTS for '.$file); return StorageHelper::showOrDownloadFile($file, $log->filename);
Log::debug('URL should be '.Storage::url($file)); } catch (\Exception $e) {
return redirect()->route('components.show', ['component' => $component])->with('error', trans('general.file_not_found'));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
} }
} }
return redirect()->route('components.show', ['component' => $component])->with('error', trans('general.log_record_not_found'));
} }
return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId])); return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));

View file

@ -104,7 +104,6 @@ class ConsumablesFilesController extends Controller
* @since [v1.4] * @since [v1.4]
* @param int $consumableId * @param int $consumableId
* @param int $fileId * @param int $fileId
* @return \Symfony\Consumable\HttpFoundation\Response
* @throws \Illuminate\Auth\Access\AuthorizationException * @throws \Illuminate\Auth\Access\AuthorizationException
*/ */
public function show($consumableId = null, $fileId = null) public function show($consumableId = null, $fileId = null)
@ -116,36 +115,18 @@ class ConsumablesFilesController extends Controller
$this->authorize('view', $consumable); $this->authorize('view', $consumable);
$this->authorize('consumables.files', $consumable); $this->authorize('consumables.files', $consumable);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $consumable->id)->find($fileId)) { if ($log = Actionlog::whereNotNull('filename')->where('item_id', $consumable->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
$file = 'private_uploads/consumables/'.$log->filename; $file = 'private_uploads/consumables/'.$log->filename;
if (Storage::missing($file)) { try {
Log::debug('FILE DOES NOT EXISTS for '.$file); return StorageHelper::showOrDownloadFile($file, $log->filename);
Log::debug('URL should be '.Storage::url($file)); } catch (\Exception $e) {
return redirect()->route('consumables.show', ['consumable' => $consumable])->with('error', trans('general.file_not_found'));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
// Display the file inline
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
// won't work, as they're not accessible via the web
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
} }
} }
// The log record doesn't exist somehow
return redirect()->route('consumables.show', ['consumable' => $consumable])->with('error', trans('general.log_record_not_found'));
} }
return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId])); return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));

View file

@ -112,37 +112,19 @@ class LicenseFilesController extends Controller
$this->authorize('view', $license); $this->authorize('view', $license);
$this->authorize('licenses.files', $license); $this->authorize('licenses.files', $license);
if (! $log = Actionlog::whereNotNull('filename')->where('item_id', $license->id)->find($fileId)) { if ($log = Actionlog::whereNotNull('filename')->where('item_id', $license->id)->find($fileId)) {
return response('No matching record for that asset/file', 500)
->header('Content-Type', 'text/plain');
}
$file = 'private_uploads/licenses/'.$log->filename; $file = 'private_uploads/licenses/'.$log->filename;
if (Storage::missing($file)) { try {
Log::debug('NOT EXISTS for '.$file); return StorageHelper::showOrDownloadFile($file, $log->filename);
Log::debug('NOT EXISTS URL should be '.Storage::url($file)); } catch (\Exception $e) {
return redirect()->route('licenses.show', ['licenses' => $license])->with('error', trans('general.file_not_found'));
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
->header('Content-Type', 'text/plain');
} else {
if (request('inline') == 'true') {
$headers = [
'Content-Disposition' => 'inline',
];
return Storage::download($file, $log->filename, $headers);
}
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
// won't work, as they're not accessible via the web
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
return StorageHelper::downloader($file);
} }
} }
// The log record doesn't exist somehow
return redirect()->route('licenses.show', ['licenses' => $license])->with('error', trans('general.log_record_not_found'));
} }
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', ['id' => $fileId])); return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', ['id' => $fileId]));

View file

@ -7,9 +7,6 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest; use App\Http\Requests\UploadFileRequest;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Response;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
@ -116,31 +113,30 @@ class UserFilesController extends Controller
public function show($userId = null, $fileId = null) public function show($userId = null, $fileId = null)
{ {
if (empty($fileId)) { if (empty($fileId)) {
return redirect()->route('users.show')->with('error', 'Invalid file request'); return redirect()->route('users.show')->with('error', 'Invalid file request');
} }
$user = User::find($userId); if ($user = User::find($userId)) {
// the license is valid
if (isset($user->id)) {
$this->authorize('view', $user); $this->authorize('view', $user);
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) { if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) {
$file = 'private_uploads/users/'.$log->filename;
// Display the file inline try {
if (request('inline') == 'true') { return StorageHelper::showOrDownloadFile($file, $log->filename);
$headers = [ } catch (\Exception $e) {
'Content-Disposition' => 'inline', return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.file_not_found'));
]; }
return Storage::download('private_uploads/users/'.$log->filename, $log->filename, $headers);
} }
return Storage::download('private_uploads/users/'.$log->filename); // The log record doesn't exist somehow
} return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.log_record_not_found'));
return redirect()->route('users.index')->with('error', trans('admin/users/message.log_record_not_found'));
return redirect()->back()->with('error', trans('general.file_not_found'));
} }
// Redirect to the user management page if the user doesn't exist // Redirect to the user management page if the user doesn't exist

View file

@ -160,7 +160,6 @@ class ActionlogsTransformer
[ [
'url' => $file_url, 'url' => $file_url,
'filename' => $actionlog->filename, 'filename' => $actionlog->filename,
'inlineable' => (bool) Helper::show_file_inline($actionlog->filename),
] : null, ] : null,
'item' => ($actionlog->item) ? [ 'item' => ($actionlog->item) ? [

View file

@ -280,7 +280,6 @@ return [
Illuminate\Redis\RedisServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class, Illuminate\Session\SessionServiceProvider::class,
// Illuminate\Translation\TranslationServiceProvider::class, //replaced on next line
App\Providers\SnipeTranslationServiceProvider::class, //we REPLACE the default Laravel translator with our own App\Providers\SnipeTranslationServiceProvider::class, //we REPLACE the default Laravel translator with our own
Illuminate\Validation\ValidationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class, Illuminate\View\ViewServiceProvider::class,
@ -373,7 +372,7 @@ return [
'Image' => Intervention\Image\ImageServiceProvider::class, 'Image' => Intervention\Image\ImageServiceProvider::class,
'Carbon' => Carbon\Carbon::class, 'Carbon' => Carbon\Carbon::class,
'Helper' => App\Helpers\Helper::class, 'Helper' => App\Helpers\Helper::class,
// makes it much easier to use 'Helper::blah' in blades (which is where we usually use this) 'StorageHelper' => App\Helpers\StorageHelper::class,
'Icon' => App\Helpers\IconHelper::class, 'Icon' => App\Helpers\IconHelper::class,
'Socialite' => Laravel\Socialite\Facades\Socialite::class, 'Socialite' => Laravel\Socialite\Facades\Socialite::class,

View file

@ -434,6 +434,7 @@ return [
'alt_uploaded_image_thumbnail' => 'Uploaded thumbnail', 'alt_uploaded_image_thumbnail' => 'Uploaded thumbnail',
'placeholder_kit' => 'Select a kit', 'placeholder_kit' => 'Select a kit',
'file_not_found' => 'File not found', 'file_not_found' => 'File not found',
'log_record_not_found' => 'No record for that log entry was found.',
'preview_not_available' => '(no preview)', 'preview_not_available' => '(no preview)',
'setup' => 'Setup', 'setup' => 'Setup',
'pre_flight' => 'Pre-Flight', 'pre_flight' => 'Pre-Flight',

View file

@ -155,98 +155,13 @@
@can('accessories.files', $accessory) @can('accessories.files', $accessory)
<div class="tab-pane" id="files"> <div class="tab-pane" id="files">
<div class="table table-responsive">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<table <x-filestable
data-cookie-id-table="accessoryUploadsTable" filepath="private_uploads/accessories/"
data-id-table="accessoryUploadsTable" showfile_routename="show.accessoryfile"
id="accessoryUploadsTable" deletefile_routename="delete/accessoryfile"
data-search="true" :object="$accessory" />
data-pagination="true"
data-side-pagination="client"
data-show-columns="true"
data-show-export="true"
data-show-footer="true"
data-toolbar="#upload-toolbar"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "export-accessories-uploads-{{ str_slug($accessory->name) }}-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","delete","download","icon"]
}'>
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@if ($accessory->uploads->count() > 0)
@foreach ($accessory->uploads as $file)
<tr>
<td>
<i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i>
<span class="sr-only">{{ Helper::filetype_icon($file->filename) }}</span>
</td>
<td>
@if ($file->filename)
@if ( Helper::checkUploadIsImage($file->get_src('accessories')))
<a href="{{ route('show.accessoryfile', ['accessoryId' => $accessory->id, 'fileId' => $file->id, 'download' => 'false']) }}" data-toggle="lightbox" data-type="image"><img src="{{ route('show.accessoryfile', ['accessoryId' => $accessory->id, 'fileId' => $file->id]) }}" class="img-thumbnail" style="max-width: 50px;"></a>
@endif
@endif
</td>
<td>
{{ $file->filename }}
</td>
<td data-value="{{ (Storage::exists('private_uploads/accessories/'.$file->filename) ? Storage::size('private_uploads/accessories/'.$file->filename) : '') }}">
{{ @Helper::formatFilesizeUnits(Storage::exists('private_uploads/accessories/'.$file->filename) ? Storage::size('private_uploads/accessories/'.$file->filename) : '') }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td style="white-space: nowrap;">
@if ($file->filename)
<a href="{{ route('show.accessoryfile', [$accessory->id, $file->id]) }}" class="btn btn-sm btn-default">
<i class="fas fa-download" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.download') }}</span>
</a>
<a href="{{ route('show.accessoryfile', [$accessory->id, $file->id, 'inline' => 'true']) }}" class="btn btn-sm btn-default" target="_blank">
<x-icon type="external-link" />
</a>
@endif
</td>
<td>{{ $file->created_at }}</td>
<td>
<a class="btn delete-asset btn-danger btn-sm" href="{{ route('delete/accessoryfile', [$accessory->id, $file->id]) }}" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}" data-title="{{ trans('general.delete') }}">
<i class="fas fa-trash icon-white" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.delete') }}</span>
</a>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="8">{{ trans('general.no_results') }}</td>
</tr>
@endif
</tbody>
</table>
</div>
</div> </div>
</div> </div>
</div> <!-- /.tab-pane --> </div> <!-- /.tab-pane -->

View file

@ -0,0 +1,142 @@
<!-- begin redirect submit options -->
@props([
'filepath',
'object',
'showfile_routename',
'deletefile_routename',
])
<!-- begin non-ajaxed file listing table -->
<div class="table-responsive">
<table
data-cookie-id-table="{{ str_slug($object->name) }}UploadsTable"
data-id-table="{{ str_slug($object->name) }}UploadsTable"
id="{{ str_slug($object->name) }}}UploadsTable"
data-search="true"
data-pagination="true"
data-side-pagination="client"
data-show-columns="true"
data-show-fullscreen="true"
data-show-export="true"
data-show-footer="true"
data-toolbar="#upload-toolbar"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "export-license-uploads-{{ str_slug($object->name) }}-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","delete","download","icon"]
}'>
<thead>
<tr>
<th data-visible="false" data-field="id" data-sortable="true">
{{trans('general.id')}}
</th>
<th data-visible="true" data-field="type" data-sortable="true">
{{trans('general.file_type')}}
</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">
{{ trans('general.image') }}
</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">
{{ trans('general.file_name') }}
</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">
{{ trans('general.filesize') }}
</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">
{{ trans('general.notes') }}
</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">
{{ trans('general.download') }}
</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">
{{ trans('general.created_at') }}
</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_by" data-sortable="true">
{{ trans('general.created_by') }}
</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">
{{ trans('table.actions') }}
</th>
</tr>
</thead>
<tbody>
@foreach ($object->uploads as $file)
<tr>
<td>
{{ $file->id }}
</td>
<td data-sort-value="{{ pathinfo($filepath.$file->filename, PATHINFO_EXTENSION) }}">
@if (Storage::exists($filepath.$file->filename))
<span class="sr-only">{{ pathinfo($filepath.$file->filename, PATHINFO_EXTENSION) }}</span>
<i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true" data-tooltip="true" data-title="{{ pathinfo($filepath.$file->filename, PATHINFO_EXTENSION) }}"></i>
@endif
</td>
<td>
@if (($file->filename) && (Storage::exists($filepath.$file->filename)))
@if (Helper::checkUploadIsImage($file->get_src(str_plural(strtolower(class_basename(get_class($object)))))))
<a href="{{ route($showfile_routename, [$object->id, $file->id, 'inline' => 'true']) }}" data-toggle="lightbox" data-type="image">
<img src="{{ route($showfile_routename, [$object->id, $file->id, 'inline' => 'true']) }}" class="img-thumbnail" style="max-width: 50px;">
</a>
@else
{{ trans('general.preview_not_available') }}
@endif
@else
<x-icon type="x" class="text-danger" />
{{ trans('general.file_not_found') }}
@endif
</td>
<td>
{{ $file->filename }}
</td>
<td data-value="{{ (Storage::exists($filepath.$file->filename)) ? Storage::size($filepath.$file->filename) : '' }}">
{{ (Storage::exists($filepath.$file->filename)) ? Helper::formatFilesizeUnits(Storage::size($filepath.$file->filename)) : '' }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td style="white-space: nowrap;">
@if ($file->filename)
@if (Storage::exists($filepath.$file->filename))
<a href="{{ route($showfile_routename, [$object->id, $file->id]) }}" class="btn btn-sm btn-default">
<x-icon type="download" />
<span class="sr-only">
{{ trans('general.download') }}
</span>
</a>
<a href="{{ StorageHelper::allowSafeInline($filepath.$file->filename) ? route($showfile_routename, [$object->id, $file->id, 'inline' => 'true']) : '#' }}" class="btn btn-sm btn-default{{ StorageHelper::allowSafeInline($filepath.$file->filename) ? '' : ' disabled' }}" target="_blank">
<x-icon type="external-link" />
</a>
@endif
@endif
</td>
<td>
{{ $file->created_at }}
</td>
<td>
{{ $file->created_by }}
</td>
<td>
<a class="btn delete-asset btn-danger btn-sm hidden-print" href="{{ route($deletefile_routename, [$object->id, $file->id]) }}" data-content="Are you sure you wish to delete this file?" data-title="{{ trans('general.delete') }} {{ $file->filename }}?">
<x-icon type="delete" />
<span class="sr-only">{{ trans('general.delete') }}</span>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<!-- end non-ajaxed file listing table -->

View file

@ -140,96 +140,14 @@
@can('components.files', $component) @can('components.files', $component)
<div class="tab-pane" id="files"> <div class="tab-pane" id="files">
<div class="row">
<div class="table-responsive"> <div class="col-md-12">
<table <x-filestable
data-cookie-id-table="componentUploadsTable" filepath="private_uploads/components/"
data-id-table="componentUploadsTable" showfile_routename="show.componentfile"
id="componentUploadsTable" deletefile_routename="delete/componentfile"
data-search="true" :object="$component" />
data-pagination="true" </div>
data-side-pagination="client"
data-show-columns="true"
data-show-export="true"
data-show-footer="true"
data-toolbar="#upload-toolbar"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "export-components-uploads-{{ str_slug($component->name) }}-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","delete","download","icon"]
}'>
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@if ($component->uploads->count() > 0)
@foreach ($component->uploads as $file)
<tr>
<td>
<i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i>
<span class="sr-only">{{ Helper::filetype_icon($file->filename) }}</span>
</td>
<td>
@if ($file->filename)
@if ( Helper::checkUploadIsImage($file->get_src('components')))
<a href="{{ route('show.componentfile', ['componentId' => $component->id, 'fileId' => $file->id, 'download' => 'false']) }}" data-toggle="lightbox" data-type="image"><img src="{{ route('show.componentfile', ['componentId' => $component->id, 'fileId' => $file->id]) }}" class="img-thumbnail" style="max-width: 50px;"></a>
@endif
@endif
</td>
<td>
{{ $file->filename }}
</td>
<td data-value="{{ (Storage::exists('private_uploads/components/'.$file->filename) ? Storage::size('private_uploads/components/'.$file->filename) : '') }}">
{{ @Helper::formatFilesizeUnits(Storage::exists('private_uploads/components/'.$file->filename) ? Storage::size('private_uploads/components/'.$file->filename) : '') }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td>
@if ($file->filename)
<nobr><a href="{{ route('show.componentfile', [$component->id, $file->id]) }}" class="btn btn-sm btn-default">
<x-icon type="download" />
<span class="sr-only">{{ trans('general.download') }}</span>
</a>
<a href="{{ route('show.componentfile', [$component->id, $file->id, 'inline' => 'true']) }}" class="btn btn-sm btn-default" target="_blank">
<x-icon type="external-link" />
</a>
</nobr>
@endif
</td>
<td>{{ $file->created_at }}</td>
<td>
<a class="btn delete-asset btn-danger btn-sm" href="{{ route('delete/componentfile', [$component->id, $file->id]) }}" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}" data-title="{{ trans('general.delete') }}">
<i class="fas fa-trash icon-white" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.delete') }}</span>
</a>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="8">{{ trans('general.no_results') }}</td>
</tr>
@endif
</tbody>
</table>
</div> </div>
</div> <!-- /.tab-pane --> </div> <!-- /.tab-pane -->
@endcan @endcan

View file

@ -428,102 +428,18 @@
<div class="tab-pane" id="files"> <div class="tab-pane" id="files">
<div class="row"> <div class="row">
<div class="col-md-12">
<x-filestable
filepath="private_uploads/consumables/"
showfile_routename="show.consumablefile"
deletefile_routename="delete/consumablefile"
:object="$consumable" />
<div class="col-md-12 col-sm-12">
<div class="table-responsive">
<table
data-cookie-id-table="consumableUploadsTable"
data-id-table="consumableUploadsTable"
id="consumableUploadsTable"
data-search="true"
data-pagination="true"
data-side-pagination="client"
data-show-columns="true"
data-show-export="true"
data-show-footer="true"
data-toolbar="#upload-toolbar"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "export-consumables-uploads-{{ str_slug($consumable->name) }}-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","delete","download","icon"]
}'>
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@if ($consumable->uploads->count() > 0)
@foreach ($consumable->uploads as $file)
<tr>
<td>
<i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i>
<span class="sr-only">{{ Helper::filetype_icon($file->filename) }}</span>
</td>
<td>
@if ($file->filename)
@if ( Helper::checkUploadIsImage($file->get_src('consumables')))
<a href="{{ route('show.consumablefile', ['consumableId' => $consumable->id, 'fileId' => $file->id, 'download' => 'false']) }}" data-toggle="lightbox" data-type="image"><img src="{{ route('show.consumablefile', ['consumableId' => $consumable->id, 'fileId' => $file->id]) }}" class="img-thumbnail" style="max-width: 50px;"></a>
@endif
@endif
</td>
<td>
{{ $file->filename }}
</td>
<td data-value="{{ (Storage::exists('private_uploads/consumables/'.$file->filename) ? Storage::size('private_uploads/consumables/'.$file->filename) : '') }}">
{{ @Helper::formatFilesizeUnits(Storage::exists('private_uploads/consumables/'.$file->filename) ? Storage::size('private_uploads/consumables/'.$file->filename) : '') }}
</td>
<td>
@if ($file->note)
{!! nl2br(Helper::parseEscapedMarkedownInline($file->note)) !!}
@endif
</td>
<td>
@if ($file->filename)
<a href="{{ route('show.consumablefile', [$consumable->id, $file->id]) }}" class="btn btn-sm btn-default">
<i class="fas fa-download" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.download') }}</span>
</a>
<a href="{{ route('show.consumablefile', [$consumable->id, $file->id, 'inline' => 'true']) }}" class="btn btn-sm btn-default" target="_blank">
<x-icon type="external-link" />
</a>
@endif
</td>
<td>{{ $file->created_at }}</td>
<td>
<a class="btn delete-asset btn-danger btn-sm" href="{{ route('delete/consumablefile', [$consumable->id, $file->id]) }}" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}" data-title="{{ trans('general.delete') }}">
<i class="fas fa-trash icon-white" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.delete') }}</span>
</a>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="8">{{ trans('general.no_results') }}</td>
</tr>
@endif
</tbody>
</table>
</div> </div>
</div> </div>
</div> <!--/ROW-->
</div><!--/FILES--> </div><!--/FILES-->
<div class="tab-pane" id="history"> <div class="tab-pane" id="history">

View file

@ -1362,102 +1362,11 @@
<div class="tab-pane fade" id="files"> <div class="tab-pane fade" id="files">
<div class="row{{ ($asset->uploads->count() > 0 ) ? '' : ' hidden-print' }}"> <div class="row{{ ($asset->uploads->count() > 0 ) ? '' : ' hidden-print' }}">
<div class="col-md-12"> <div class="col-md-12">
<x-filestable
@if ($asset->uploads->count() > 0) filepath="private_uploads/assets/"
<table showfile_routename="show/assetfile"
class="table table-striped snipe-table" deletefile_routename="delete/modelfile"
id="assetFileHistory" :object="$asset" />
data-pagination="true"
data-id-table="assetFileHistory"
data-search="true"
data-side-pagination="client"
data-sortable="true"
data-show-columns="true"
data-show-fullscreen="true"
data-show-refresh="true"
data-sort-order="desc"
data-sort-name="created_at"
data-show-export="true"
data-export-options='{
"fileName": "export-asset-{{ $asset->id }}-files",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
}'
data-cookie-id-table="assetFileHistory">
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach ($asset->uploads as $file)
<tr>
<td><i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i></td>
<td>
@if ( Helper::checkUploadIsImage($file->get_src('assets')))
<a href="{{ route('show/assetfile', ['assetId' => $asset->id, 'fileId' =>$file->id]) }}" data-toggle="lightbox" data-type="image" data-title="{{ $file->filename }}" data-footer="{{ Helper::getFormattedDateObject($asset->last_checkout, 'datetime', false) }}">
<img src="{{ route('show/assetfile', ['assetId' => $asset->id, 'fileId' =>$file->id]) }}" style="max-width: 50px;">
</a>
@endif
</td>
<td>
@if (Storage::exists('private_uploads/assets/'.$file->filename))
{{ $file->filename }}
@else
<del>{{ $file->filename }}</del>
@endif
</td>
<td data-value="{{ (Storage::exists('private_uploads/assets/'.$file->filename) ? Storage::size('private_uploads/assets/'.$file->filename) : '') }}">
{{ @Helper::formatFilesizeUnits(Storage::exists('private_uploads/assets/'.$file->filename) ? Storage::size('private_uploads/assets/'.$file->filename) : '') }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td>
@if (($file->filename) && (Storage::exists('private_uploads/assets/'.$file->filename)))
<a href="{{ route('show/assetfile', [$asset->id, $file->id, 'download'=>'true']) }}" class="btn btn-sm btn-default hidden-print">
<x-icon type="download" />
</a>
<a href="{{ route('show/assetfile', [$asset->id, $file->id, 'inline'=>'true']) }}" class="btn btn-sm btn-default hidden-print" target="_blank">
<x-icon type="external-link" />
</a>
@endif
</td>
<td>
@if ($file->created_at)
{{ Helper::getFormattedDateObject($file->created_at, 'datetime', false) }}
@endif
</td>
<td>
@can('update', \App\Models\Asset::class)
<a class="btn delete-asset btn-sm btn-danger btn-sm hidden-print" href="{{ route('delete/assetfile', [$asset->id, $file->id]) }}" data-tooltip="true" data-title="Delete" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}">
<x-icon type="delete" />
</a>
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="alert alert-info alert-block hidden-print">
<x-icon type="info-circle" />
{{ trans('general.no_results') }}
</div>
@endif
</div> <!-- /.col-md-12 --> </div> <!-- /.col-md-12 -->
</div> <!-- /.row --> </div> <!-- /.row -->
</div> <!-- /.tab-pane files --> </div> <!-- /.tab-pane files -->
@ -1467,101 +1376,11 @@
<div class="row{{ (($asset->model) && ($asset->model->uploads->count() > 0)) ? '' : ' hidden-print' }}"> <div class="row{{ (($asset->model) && ($asset->model->uploads->count() > 0)) ? '' : ' hidden-print' }}">
<div class="col-md-12"> <div class="col-md-12">
@if (($asset->model) && ($asset->model->uploads->count() > 0)) <x-filestable
<table filepath="private_uploads/assetmodels/"
class="table table-striped snipe-table" showfile_routename="show/modelfile"
id="assetModelFileHistory" deletefile_routename="userfile.destroy"
data-pagination="true" :object="$asset->model" />
data-id-table="assetModelFileHistory"
data-search="true"
data-side-pagination="client"
data-sortable="true"
data-show-columns="true"
data-show-fullscreen="true"
data-show-refresh="true"
data-sort-order="desc"
data-sort-name="created_at"
data-show-export="true"
data-export-options='{
"fileName": "export-assetmodel-{{ $asset->model->id }}-files",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
}'
data-cookie-id-table="assetFileHistory">
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach ($asset->model->uploads as $file)
<tr>
<td><i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i></td>
<td>
@if ( Helper::checkUploadIsImage($file->get_src('assetmodels')))
<a href="{{ route('show/modelfile', ['modelID' => $asset->model->id, 'fileId' =>$file->id]) }}" data-toggle="lightbox" data-type="image" data-title="{{ $file->filename }}" data-footer="{{ Helper::getFormattedDateObject($asset->last_checkout, 'datetime', false) }}">
<img src="{{ route('show/modelfile', ['modelID' => $asset->model->id, 'fileId' =>$file->id]) }}" style="max-width: 50px;">
</a>
@endif
</td>
<td>
@if (Storage::exists('private_uploads/assetmodels/'.$file->filename))
{{ $file->filename }}
@else
<del>{{ $file->filename }}</del>
@endif
</td>
<td data-value="{{ (Storage::exists('private_uploads/assetmodels/'.$file->filename)) ? Storage::size('private_uploads/assetmodels/'.$file->filename) : '' }}">
{{ (Storage::exists('private_uploads/assetmodels/'.$file->filename)) ? Helper::formatFilesizeUnits(Storage::size('private_uploads/assetmodels/'.$file->filename)) : '' }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td>
@if (($file->filename) && (Storage::exists('private_uploads/assetmodels/'.$file->filename)))
<a href="{{ route('show/modelfile', [$asset->model->id, $file->id]) }}" class="btn btn-sm btn-default hidden-print">
<x-icon type="download" class="hidden-print" />
</a>
<a href="{{ route('show/modelfile', [$asset->model->id, $file->id, 'inline'=>'true']) }}" class="btn btn-sm btn-default hidden-print" target="_blank">
<x-icon type="external-link" class="hidden-print" />
</a>
@endif
</td>
<td>
@if ($file->created_at)
{{ Helper::getFormattedDateObject($file->created_at, 'datetime', false) }}
@endif
</td>
<td>
@can('update', \App\Models\AssetModel::class)
<a class="btn delete-asset btn-sm btn-danger btn-sm hidden-print" href="{{ route('delete/modelfile', [$asset->model->id, $file->id]) }}" data-tooltip="true" data-title="Delete" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}">
<x-icon type="delete" class="hidden-print"/></i>
</a>
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="alert alert-info alert-block">
<x-icon type="info-circle" />
{{ trans('general.no_results') }}
</div>
@endif
</div> <!-- /.col-md-12 --> </div> <!-- /.col-md-12 -->
</div> <!-- /.row --> </div> <!-- /.row -->

View file

@ -464,100 +464,13 @@
@can('licenses.files', $license) @can('licenses.files', $license)
<div class="tab-pane" id="files"> <div class="tab-pane" id="files">
<div class="table-responsive">
<table
data-cookie-id-table="licenseUploadsTable"
data-id-table="licenseUploadsTable"
id="licenseUploadsTable"
data-search="true"
data-pagination="true"
data-side-pagination="client"
data-show-columns="true"
data-show-export="true"
data-show-footer="true"
data-toolbar="#upload-toolbar"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "export-license-uploads-{{ str_slug($license->name) }}-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","delete","download","icon"]
}'>
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@if ($license->uploads->count() > 0)
@foreach ($license->uploads as $file)
<tr>
<td>
<i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i>
<span class="sr-only">{{ Helper::filetype_icon($file->filename) }}</span>
</td> <x-filestable
<td> filepath="private_uploads/licenses/"
@if ($file->filename) showfile_routename="show.licensefile"
@if ((Storage::exists('private_uploads/licenses/'.$file->filename)) && ( Helper::checkUploadIsImage($file->get_src('licenses')))) deletefile_routename="delete/licensefile"
<a href="{{ route('show.licensefile', ['licenseId' => $license->id, 'fileId' => $file->id, 'download' => 'false']) }}" data-toggle="lightbox" data-type="image"><img src="{{ route('show.licensefile', ['licenseId' => $license->id, 'fileId' => $file->id]) }}" class="img-thumbnail" style="max-width: 50px;"></a> :object="$license" />
@endif
@endif
</td>
<td>
@if (Storage::exists('private_uploads/licenses/'.$file->filename))
{{ $file->filename }}
@else
<del>{{ $file->filename }}</del>
@endif
</td>
<td data-value="{{ (Storage::exists('private_uploads/licenses/'.$file->filename)) ? Storage::size('private_uploads/licenses/'.$file->filename) : '' }}">
{{ (Storage::exists('private_uploads/licenses/'.$file->filename)) ? Helper::formatFilesizeUnits(Storage::size('private_uploads/licenses/'.$file->filename)) : '' }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td>
@if ($file->filename)
<a href="{{ route('show.licensefile', [$license->id, $file->id]) }}" class="btn btn-sm btn-default">
<x-icon type="download"/>
<span class="sr-only">{{ trans('general.download') }}</span>
</a>
<a href="{{ route('show.licensefile', [$license->id, $file->id, 'inline' => 'true']) }}" class="btn btn-sm btn-default" target="_blank">
<x-icon type="external-link" />
</a>
@endif
</td>
<td>{{ $file->created_at }}</td>
<td>
<a class="btn delete-asset btn-danger btn-sm" href="{{ route('delete/licensefile', [$license->id, $file->id]) }}" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}" data-title="{{ trans('general.delete') }}">
<x-icon type="delete" />
<span class="sr-only">{{ trans('general.delete') }}</span>
</a>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="8">{{ trans('general.no_results') }}</td>
</tr>
@endif
</tbody>
</table>
</div>
</div> <!-- /.tab-pane --> </div> <!-- /.tab-pane -->
@endcan @endcan

View file

@ -107,99 +107,11 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@if ($model->uploads->count() > 0) <x-filestable
<table filepath="private_uploads/assetmodels/"
class="table table-striped snipe-table" showfile_routename="show/modelfile"
id="modelFileHistory" deletefile_routename="delete/modelfile"
data-pagination="true" :object="$model" />
data-id-table="modelFileHistory"
data-search="true"
data-side-pagination="client"
data-sortable="true"
data-show-columns="true"
data-show-fullscreen="true"
data-show-refresh="true"
data-sort-order="desc"
data-sort-name="created_at"
data-show-export="true"
data-export-options='{
"fileName": "export-asset-{{ $model->id }}-files",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
}'
data-cookie-id-table="assetFileHistory">
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach ($model->uploads as $file)
<tr>
<td><i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i></td>
<td>
@if ((Storage::exists('private_uploads/assetmodels/'.$file->filename)) && ( Helper::checkUploadIsImage($file->get_src('assetmodels'))))
<a href="{{ route('show/modelfile', ['modelID' => $model->id, 'fileId' => $file->id]) }}" data-toggle="lightbox" data-type="image" data-title="{{ $file->filename }}">
<img src="{{ route('show/modelfile', ['modelID' => $model->id, 'fileId' =>$file->id]) }}" style="max-width: 50px;">
</a>
@endif
</td>
<td>
@if (Storage::exists('private_uploads/assetmodels/'.$file->filename))
{{ $file->filename }}
@else
<del>{{ $file->filename }}</del>
@endif
</td>
<td data-value="{{ (Storage::exists('private_uploads/assetmodels/'.$file->filename)) ? Storage::size('private_uploads/assetmodels/'.$file->filename) : '' }}">
{{ (Storage::exists('private_uploads/assetmodels/'.$file->filename)) ? Helper::formatFilesizeUnits(Storage::size('private_uploads/assetmodels/'.$file->filename)) : '' }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td style="white-space: nowrap">
@if (($file->filename) && (Storage::exists('private_uploads/assetmodels/'.$file->filename)))
<a href="{{ route('show/modelfile', [$model->id, $file->id]) }}" class="btn btn-sm btn-default">
<i class="fas fa-download" aria-hidden="true"></i>
</a>
<a href="{{ route('show/modelfile', [$model->id, $file->id, 'inline'=>'true']) }}" class="btn btn-sm btn-default" target="_blank">
<x-icon type="external-link" />
</a>
@endif
</td>
<td>
@if ($file->created_at)
{{ Helper::getFormattedDateObject($file->created_at, 'datetime', false) }}
@endif
</td>
<td>
@can('update', \App\Models\AssetModel::class)
<a class="btn delete-asset btn-sm btn-danger btn-sm" href="{{ route('delete/assetfile', [$model->id, $file->id]) }}" data-tooltip="true" data-title="Delete" data-content="{{ trans('general.delete_confirm', ['item' => $file->filename]) }}"><i class="fas fa-trash icon-white" aria-hidden="true"></i></a>
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="alert alert-info alert-block">
<i class="fas fa-info-circle"></i>
{{ trans('general.no_results') }}
</div>
@endif
</div> <!-- /.col-md-12 --> </div> <!-- /.col-md-12 -->
</div> <!-- /.row --> </div> <!-- /.row -->

View file

@ -971,102 +971,11 @@
<div class="row"> <div class="row">
<div class="col-md-12 col-sm-12"> <div class="col-md-12 col-sm-12">
<div class="table-responsive"> <x-filestable
<table filepath="private_uploads/users/"
data-cookie-id-table="userUploadsTable" showfile_routename="show/userfile"
data-id-table="userUploadsTable" deletefile_routename="userfile.destroy"
id="userUploadsTable" :object="$user" />
data-search="true"
data-pagination="true"
data-side-pagination="client"
data-show-columns="true"
data-show-fullscreen="true"
data-show-export="true"
data-show-footer="true"
data-toolbar="#upload-toolbar"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "export-license-uploads-{{ str_slug($user->name) }}-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","delete","download","icon"]
}'>
<thead>
<tr>
<th data-visible="true" data-field="icon" data-sortable="true">{{trans('general.file_type')}}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename" data-sortable="true">{{ trans('general.file_name') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="filesize">{{ trans('general.filesize') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes" data-sortable="true">{{ trans('general.notes') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="download">{{ trans('general.download') }}</th>
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="created_at" data-sortable="true">{{ trans('general.created_at') }}</th>
<th class="col-md-1" data-searchable="true" data-visible="true" data-field="actions">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach ($user->uploads as $file)
<tr>
<td>
<i class="{{ Helper::filetype_icon($file->filename) }} icon-med" aria-hidden="true"></i>
<span class="sr-only">{{ Helper::filetype_icon($file->filename) }}</span>
</td>
<td>
@if (($file->filename) && (Storage::exists('private_uploads/users/'.$file->filename)))
@if (Helper::checkUploadIsImage($file->get_src('users')))
<a href="{{ route('show/userfile', [$user->id, $file->id, 'inline' => 'true']) }}" data-toggle="lightbox" data-type="image"><img src="{{ route('show/userfile', [$user->id, $file->id, 'inline' => 'true']) }}" class="img-thumbnail" style="max-width: 50px;"></a>
@else
{{ trans('general.preview_not_available') }}
@endif
@else
<x-icon type="x" class="text-danger" />
{{ trans('general.file_not_found') }}
@endif
</td>
<td>
{{ $file->filename }}
</td>
<td data-value="{{ (Storage::exists('private_uploads/users/'.$file->filename)) ? Storage::size('private_uploads/users/'.$file->filename) : '' }}">
{{ (Storage::exists('private_uploads/users/'.$file->filename)) ? Helper::formatFilesizeUnits(Storage::size('private_uploads/users/'.$file->filename)) : '' }}
</td>
<td>
@if ($file->note)
{{ $file->note }}
@endif
</td>
<td>
@if ($file->filename)
@if (Storage::exists('private_uploads/users/'.$file->filename))
<a href="{{ route('show/userfile', [$user->id, $file->id]) }}" class="btn btn-sm btn-default">
<x-icon type="download" />
<span class="sr-only">{{ trans('general.download') }}</span>
</a>
<a href="{{ route('show/userfile', [$user->id, $file->id, 'inline' => 'true']) }}" class="btn btn-sm btn-default" target="_blank">
<x-icon type="external-link" />
</a>
@endif
@endif
</td>
<td>{{ $file->created_at }}</td>
<td>
<a class="btn delete-asset btn-danger btn-sm hidden-print" href="{{ route('userfile.destroy', [$user->id, $file->id]) }}" data-content="Are you sure you wish to delete this file?" data-title="{{ trans('general.delete') }} {{ $file->filename }}?">
<x-icon type="delete" />
<span class="sr-only">{{ trans('general.delete') }}</span>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div> </div>
</div> <!--/ROW--> </div> <!--/ROW-->
</div><!--/FILES--> </div><!--/FILES-->