Merge branch 'develop' into livewire_importer_2_squashed_and_rebased

I'll be taking in the changes to the importer front-end elsewhere
This commit is contained in:
Brady Wetherington 2023-03-07 18:51:05 -08:00
commit 09c1298e03
60 changed files with 1515 additions and 1137 deletions

21
.github/workflows/crowdin-upload.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: Crowdin Action
on:
push:
branches: [ develop ]
jobs:
upload-sources-to-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Crowdin push
uses: crowdin/github-action@v1
with:
upload_sources: true
upload_translations: false
download_translations: false
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View file

@ -6,6 +6,7 @@ use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use App\Helpers\Helper;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\AuthenticationException;
use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
use Log;
use Throwable;
use JsonException;
@ -28,6 +29,7 @@ class Handler extends ExceptionHandler
\Intervention\Image\Exception\NotSupportedException::class,
\League\OAuth2\Server\Exception\OAuthServerException::class,
JsonException::class,
SCIMException::class, //these generally don't need to be reported
];
/**
@ -53,7 +55,7 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
*/
public function render($request, Throwable $e)
{
@ -70,6 +72,9 @@ class Handler extends ExceptionHandler
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid JSON'), 422);
}
if ($e instanceof SCIMException) {
return response()->json(Helper::formatStandardApiResponse('error', null, 'invalid SCIM Request'), 400);
}
// Handle Ajax requests that fail because the model doesn't exist
if ($request->ajax() || $request->wantsJson()) {
@ -113,8 +118,8 @@ class Handler extends ExceptionHandler
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {

View file

@ -101,6 +101,7 @@ class AssetsController extends Controller
'checkin_counter',
'requests_counter',
'byod',
'asset_eol_date',
];
$filter = [];
@ -128,7 +129,6 @@ class AssetsController extends Controller
// They are also used by the individual searches on detail pages like
// locations, etc.
// Search custom fields by column name
foreach ($all_custom_fields as $field) {
if ($request->filled($field->db_column_name())) {
@ -136,7 +136,6 @@ class AssetsController extends Controller
}
}
if ($request->filled('status_id')) {
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
@ -173,6 +172,10 @@ class AssetsController extends Controller
$assets->where('assets.supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('asset_eol_date')) {
$assets->where('assets.asset_eol_date', '=', $request->input('asset_eol_date'));
}
if (($request->filled('assigned_to')) && ($request->filled('assigned_type'))) {
$assets->where('assets.assigned_to', '=', $request->input('assigned_to'))
->where('assets.assigned_type', '=', $request->input('assigned_type'));

View file

@ -126,7 +126,14 @@ class ImportController extends Controller
}
$file_name = date('Y-m-d-his').'-'.$fixed_filename;
$import->file_path = $file_name;
$import->filesize = null;
if (!file_exists($path.'/'.$file_name)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 500);
}
$import->filesize = filesize($path.'/'.$file_name);
$import->save();
$results[] = $import;
}

View file

@ -271,7 +271,7 @@ class SettingsController extends Controller
$headers = ['ContentType' => 'application/zip'];
return Storage::download($path.'/'.$file, $file, $headers);
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, 'File not found'));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
}
}

View file

@ -196,6 +196,7 @@ class StatuslabelsController extends Controller
{
$this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::withCount('assets')->get();
$total = Array();
foreach ($statuslabels as $statuslabel) {

View file

@ -69,6 +69,7 @@ class UsersController extends Controller
'users.ldap_import',
'users.start_date',
'users.end_date',
'users.vip',
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
@ -149,6 +150,10 @@ class UsersController extends Controller
$users = $users->where('remote', '=', $request->input('remote'));
}
if ($request->filled('vip')) {
$users = $users->where('vip', '=', $request->input('vip'));
}
if ($request->filled('two_factor_enrolled')) {
$users = $users->where('two_factor_enrolled', '=', $request->input('two_factor_enrolled'));
}

View file

@ -142,6 +142,7 @@ class AssetsController extends Controller
$asset->warranty_months = request('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
$asset->purchase_date = request('purchase_date', null);
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->assigned_to = request('assigned_to', null);
$asset->supplier_id = request('supplier_id', null);
$asset->requestable = request('requestable', 0);
@ -312,6 +313,8 @@ class AssetsController extends Controller
$asset->status_id = $request->input('status_id', null);
$asset->warranty_months = $request->input('warranty_months', null);
$asset->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
$asset->asset_eol_date = request('asset_eol_date', null);
$asset->purchase_date = $request->input('purchase_date', null);
$asset->supplier_id = $request->input('supplier_id', null);
$asset->expected_checkin = $request->input('expected_checkin', null);

View file

@ -59,6 +59,12 @@ class LicenseCheckinController extends Controller
}
$license = License::find($licenseSeat->license_id);
// LicenseSeat is not assigned, it can't be checked in
if (is_null($licenseSeat->assigned_to) && is_null($licenseSeat->asset_id)) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkin.error'));
}
$this->authorize('checkout', $license);
if (! $license->reassignable) {

View file

@ -227,6 +227,36 @@ class LocationsController extends Controller
}
/**
* Returns a view that presents a form to clone a location.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v6.0.14]
* @return View
*/
public function getClone($locationId = null)
{
$this->authorize('create', Location::class);
// Check if the asset exists
if (is_null($location_to_clone = Location::find($locationId))) {
// Redirect to the asset management page
return redirect()->route('licenses.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
$location = clone $location_to_clone;
// unset these values
$location->id = null;
$location->image = null;
return view('locations/edit')
->with('item', $location);
}
public function print_all_assigned($id)
{
if ($location = Location::where('id', $id)->first()) {

View file

@ -284,7 +284,7 @@ class ReportsController extends Controller
$row = [
$actionlog->created_at,
($actionlog->user) ? e($actionlog->user->getFullNameAttribute()) : '',
($actionlog->admin) ? e($actionlog->admin->getFullNameAttribute()) : '',
$actionlog->present()->actionType(),
e($actionlog->itemType()),
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,

View file

@ -65,18 +65,27 @@ class SettingsController extends Controller
$start_settings['db_error'] = $e->getMessage();
}
$protocol = array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS']) ? 'https://' : 'http://';
if (array_key_exists("HTTP_X_FORWARDED_PROTO", $_SERVER)) {
$protocol = $_SERVER["HTTP_X_FORWARDED_PROTO"] . "://";
} elseif (array_key_exists('HTTPS', $_SERVER) && ('on' == $_SERVER['HTTPS'])) {
$protocol = "https://";
} else {
$protocol = "http://";
}
$host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null;
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null;
if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) {
$host .= ':'.$port;
if (array_key_exists("HTTP_X_FORWARDED_HOST", $_SERVER)) {
$host = $_SERVER["HTTP_X_FORWARDED_HOST"];
} else {
$host = array_key_exists('SERVER_NAME', $_SERVER) ? $_SERVER['SERVER_NAME'] : null;
$port = array_key_exists('SERVER_PORT', $_SERVER) ? $_SERVER['SERVER_PORT'] : null;
if (('http://' === $protocol && '80' != $port) || ('https://' === $protocol && '443' != $port)) {
$host .= ':'.$port;
}
}
$pageURL = $protocol.$host.$_SERVER['REQUEST_URI'];
$start_settings['url_valid'] = (url('/').'/setup' === $pageURL);
$start_settings['url_config'] = url('/');
$start_settings['url_config'] = url('/').'/setup';
$start_settings['url_valid'] = ($start_settings['url_config'] === $pageURL);
$start_settings['real_url'] = $pageURL;
$start_settings['php_version_min'] = true;
@ -111,17 +120,17 @@ class SettingsController extends Controller
$start_settings['prod'] = true;
}
$start_settings['owner'] = '';
if (function_exists('posix_getpwuid')) { // Probably Linux
$owner = posix_getpwuid(fileowner($_SERVER['SCRIPT_FILENAME']));
$start_settings['owner'] = $owner['name'];
} else { // Windows
// TODO: Is there a way of knowing if a windows user has elevated permissions
// This just gets the user name, which likely isn't 'root'
// $start_settings['owner'] = getenv('USERNAME');
$start_settings['owner'] = '';
// This *should* be an array, but we've seen this return a bool in some chrooted environments
if (is_array($owner)) {
$start_settings['owner'] = $owner['name'];
}
}
if (('root' === $start_settings['owner']) || ('0' === $start_settings['owner'])) {
if (($start_settings['owner'] === 'root') || ($start_settings['owner'] === '0')) {
$start_settings['owner_is_admin'] = true;
} else {
$start_settings['owner_is_admin'] = false;

View file

@ -38,7 +38,8 @@ class AssetsTransformer
'byod' => ($asset->byod ? true : false),
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'eol' => ($asset->purchase_date != '') ? Helper::getFormattedDateObject($asset->present()->eol_date(), 'date') : null,
'eol' => ($asset->model->eol != '') ? $asset->model->eol : null,
'asset_eol_date' => ($asset->asset_eol_date != '') ? Helper::getFormattedDateObject($asset->asset_eol_date, 'date') : null,
'status_label' => ($asset->assetstatus) ? [
'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->assetstatus->name),

View file

@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\Location;
use Gate;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;
@ -63,6 +63,7 @@ class LocationsTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Location::class) ? true : false,
'delete' => $location->isDeletable(),
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
];
$array += $permissions_array;

View file

@ -36,6 +36,7 @@ class UsersTransformer
'name'=> e($user->manager->first_name).' '.e($user->manager->last_name),
] : null,
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
'vip' => ($user->vip == '1') ? true : false,
'phone' => ($user->phone) ? e($user->phone) : null,
'website' => ($user->website) ? e($user->website) : null,
'address' => ($user->address) ? e($user->address) : null,

View file

@ -76,10 +76,12 @@ class AssetImporter extends ItemImporter
}
$this->item['notes'] = $this->findCsvMatch($row, 'asset_notes');
$this->item['image'] = $this->findCsvMatch($row, 'image');
$this->item['requestable'] = $this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'));
$asset->requestable = $this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'));
$this->item['requestable'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable')) == 1) ? '1' : 0;
$asset->requestable = $this->item['requestable'];
$this->item['warranty_months'] = intval($this->findCsvMatch($row, 'warranty_months'));
$this->item['model_id'] = $this->createOrFetchAssetModel($row);
$this->item['byod'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'byod')) == 1) ? '1' : 0;
// If no status ID is found
if (! array_key_exists('status_id', $this->item) && ! $editingAsset) {
@ -135,7 +137,7 @@ class AssetImporter extends ItemImporter
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
//-- the class that needs to use it (command importer or GUI importer inside the project).
if (isset($target)) {
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'));
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'), null, $asset->notes, $asset->name);
}
return;

View file

@ -58,6 +58,8 @@ class UserImporter extends ItemImporter
$this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department'));
$this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name'));
$this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0;
$this->item['vip'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
$user_department = $this->findCsvMatch($row, 'department');
if ($this->shouldUpdateField($user_department)) {

View file

@ -36,8 +36,10 @@
| name | | |
| email | | |
| username | | |
| address | address | User |
| city | city | User |
| state | state | User |
| country | country | User |
| address | address | User |
| city | city | User |
| state | state | User |
| country | country | User |
| vip | vip | User |
| byod | byod | Asset |

View file

@ -114,6 +114,7 @@ class Asset extends Depreciable
'serial' => 'unique_serial|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'supplier_id' => 'exists:suppliers,id|nullable',
'asset_eol_date' => 'date|max:10|min:10|nullable',
];
/**
@ -143,9 +144,9 @@ class Asset extends Depreciable
'last_checkout',
'expected_checkin',
'byod',
'asset_eol_date',
'last_audit_date',
'next_audit_date',
];
use Searchable;
@ -168,6 +169,7 @@ class Asset extends Depreciable
'expected_checkin',
'next_audit_date',
'last_audit_date',
'asset_eol_date',
];
/**
@ -181,7 +183,7 @@ class Asset extends Depreciable
'company' => ['name'],
'defaultLoc' => ['name'],
'location' => ['name'],
'model' => ['name', 'model_number'],
'model' => ['name', 'model_number', 'eol'],
'model.category' => ['name'],
'model.manufacturer' => ['name'],
];
@ -545,6 +547,28 @@ class Asset extends Depreciable
return strtolower(class_basename($this->assigned_type));
}
/**
* This is annoying, but because we don't say "assets" in our route names, we have to make an exception here
* @todo - normalize the route names - API endpoint URLS can stay the same
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.1.0]
* @return string
*/
public function targetShowRoute()
{
$route = str_plural($this->assignedType());
if ($route=='assets') {
return 'hardware';
}
return $route;
}
/**
* Get the asset's location based on default RTD location
*

View file

@ -25,7 +25,10 @@ class CheckoutAcceptance extends Model
{
// At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications.
return Setting::getSettings()->alert_email;
$recipients_string = explode(',', Setting::getSettings()->alert_email);
$recipients = array_map('trim', $recipients_string);
return array_filter($recipients);
}
/**

View file

@ -16,7 +16,7 @@ class Depreciation extends SnipeModel
// Declare the rules for the form validation
protected $rules = [
'name' => 'required|min:3|max:255|unique:depreciations,name',
'months' => 'required|max:3600|integer',
'months' => 'required|max:3600|integer|gt:0',
];
/**

View file

@ -93,8 +93,12 @@ trait Loggable
{
$settings = Setting::getSettings();
$log = new Actionlog;
$log->target_type = get_class($target);
$log->target_id = $target->id;
if($target != null){
$log->target_type = get_class($target);
$log->target_id = $target->id;
}
if (static::class == LicenseSeat::class) {
$log->item_type = License::class;

View file

@ -80,8 +80,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'created_at',
'updated_at',
'deleted_at',
'start_date',
'end_date',
'start_date' => 'date_format:Y-m-d',
'end_date' => 'date_format:Y-m-d',
];

View file

@ -163,9 +163,16 @@ class AssetPresenter extends Presenter
], [
'field' => 'eol',
'searchable' => false,
'sortable' => false,
'sortable' => true,
'visible' => false,
'title' => trans('general.eol'),
],
[
'field' => 'asset_eol_date',
'searchable' => true,
'sortable' => true,
'visible' => false,
'title' => trans('admin/hardware/form.eol_date'),
'formatter' => 'dateDisplayFormatter',
], [
'field' => 'warranty_months',

View file

@ -117,6 +117,11 @@ $config = [
\Log::info("IGNORING E_WARNING in production mode: ".$args->getMessage());
return true; // "TRUE - you should ignore it!"
}
$needle = "ArieTimmerman\\Laravel\\SCIMServer\\Exceptions\\SCIMException";
if (App::environment('production') && is_string($args) && strncmp($args, $needle, strlen($needle) ) === 0 ) {
\Log::info("String: '$args' looks like a SCIM Exception; ignoring error");
return true; //yes, *do* ignore it
}
return false;
},
],

View file

@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v6.0.14',
'full_app_version' => 'v6.0.14 - build 9599-g1415c8c6e',
'build_version' => '9599',
'full_app_version' => 'v6.0.14 - build 9646-g417a1e624',
'build_version' => '9646',
'prerelease_version' => '',
'hash_version' => 'g1415c8c6e',
'full_hash' => 'v6.0.14-555-g1415c8c6e',
'hash_version' => 'g417a1e624',
'full_hash' => 'v6.0.14-602-g417a1e624',
'branch' => 'develop',
);

View file

@ -55,7 +55,7 @@ class ActionlogFactory extends Factory
[
'assigned_to' => $target->id,
'assigned_type' => \App\Models\User::class,
'assigned_to' => $target->location_id,
'location_id' => $target->location_id,
]
);
@ -84,7 +84,7 @@ class ActionlogFactory extends Factory
[
'assigned_to' => $target->id,
'assigned_type' => \App\Models\Location::class,
'assigned_to' => $target->id,
'location_id' => $target->id,
]
);

View file

@ -46,7 +46,7 @@ class LicenseFactory extends Factory
'serial' => $this->faker->uuid,
'notes' => 'Created by DB seeder',
'seats' => $this->faker->numberBetween(1, 10),
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d'),
'order_number' => $this->faker->numberBetween(1000000, 50000000),
'expiration_date' => $this->faker->dateTimeBetween('now', '+3 years', date_default_timezone_get())->format('Y-m-d H:i:s'),
'reassignable' => $this->faker->boolean(),

View file

@ -0,0 +1,54 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Asset;
use App\Models\AssetModel;
class AddEolDateOnAssetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('assets', function (Blueprint $table) {
if (!Schema::hasColumn('assets', 'asset_eol_date')) {
$table->date('asset_eol_date')->after('purchase_date')->nullable()->default(null);
}
});
// Chunk the model query to get the models that do have an EOL date
AssetModel::whereNotNull('eol')->with('assets')->chunk(200, function ($models) {
foreach ($models as $model) {
foreach ($model->assets as $asset) {
if ($asset->purchase_date!='') {
$asset->asset_eol_date = $asset->present()->eol_date();
$asset->save();
}
}
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('assets', function (Blueprint $table) {
if (Schema::hasColumn('assets', 'asset_eol_date')) {
$table->dropColumn('asset_eol_date');
}
});
}
}

6
package-lock.json generated
View file

@ -1329,9 +1329,9 @@
"dev": true
},
"@fortawesome/fontawesome-free": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.1.tgz",
"integrity": "sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.3.0.tgz",
"integrity": "sha512-qVtd5i1Cc7cdrqnTWqTObKQHjPWAiRwjUPaXObaeNPcy7+WKxJumGBx66rfSFgK6LNpIasVKkEgW8oyf0tmPLA=="
},
"@jridgewell/gen-mapping": {
"version": "0.1.1",

View file

@ -24,7 +24,7 @@
"vue-template-compiler": "2.4.4"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.2.1",
"@fortawesome/fontawesome-free": "^6.3.0",
"acorn": "^8.8.2",
"acorn-import-assertions": "^1.8.0",
"admin-lte": "^2.4.18",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/dist/all.js vendored

Binary file not shown.

View file

@ -1,8 +1,8 @@
{
"/js/build/app.js": "/js/build/app.js?id=f05cc05b9000ba73e1949bcf137d4301",
"/js/build/app.js": "/js/build/app.js?id=790387868822daaa28dcc3722928b7b1",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374",
"/css/build/overrides.css": "/css/build/overrides.css?id=0465141b9ecb0662ba6790c1460f391f",
"/css/build/app.css": "/css/build/app.css?id=c3a896cab26e2093f8be24336b7db1b9",
"/css/build/overrides.css": "/css/build/overrides.css?id=d9175e3d9b9074397343dddebfe23888",
"/css/build/app.css": "/css/build/app.css?id=dcb8aa9f4501a370214a67442e88daf0",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=f343f659ca1d45534d2c2c3cc30fb619",
@ -18,23 +18,23 @@
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898",
"/css/dist/all.css": "/css/dist/all.css?id=ef030b613d45620b907cf0184a14e868",
"/css/dist/all.css": "/css/dist/all.css?id=0314c741a636de602ec952468eb171f3",
"/css/blue.png": "/css/blue.png?id=e83a6c29e04fe851f2122815b2e4b150",
"/css/blue@2x.png": "/css/blue@2x.png?id=51135dd4d24f88f5de0b2414bd51dac5",
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=0b834d6c0ecc5bf275a83414eb38efd4",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=a46924ee2a2a7702ef7fe7ead62fca18",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=93d1ca4fec25c46c9ac67b07058b3f72",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=d8373194363409c201ee33fcd48ba574",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=a7d60e1f645d1b80e0879b2c8e72ed06",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=3e1cccc95e0dadb2168d67c2f0f23bf3",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=ee335846f3552dc6af2ef7c8cafae1dc",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=1ad361f755ce9c96dadb8da2d7318975",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=2df05d4beaa48550d71234e8dca79141",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=682885a4f72597322017a9fcd0683831",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=e7a7f9dd9376f68614860d920255d4df",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=204fc700c679395e6aa9bebc3cada64e",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=c9d3294ec75b843a31ef711069a0f0b6",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=6707d0247b0bca1b4964bab435e3c0d6",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=a947172f4fde88e43b4c1a60b01db061",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=bbc23038a6067c78310d3f19432a3ebf",
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=ee4896df8b8f008ce73a9a0c2549aefd",
"/js/build/vendor.js": "/js/build/vendor.js?id=47ecbb4bb3b0e02315f391caadbdf971",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=14d9a2affec7b066d20fcba2e6e67ad2",
"/js/dist/all.js": "/js/dist/all.js?id=4f9355ac85d380301f6f62e55b1a6e5e",
"/js/dist/all.js": "/js/dist/all.js?id=93f3ed97355821b50ee5bbd4f658dd05",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=c0d21166315b7c2cdd4819fa4a5e4d1e",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb",

View file

@ -671,18 +671,18 @@ th.css-accessory > .th-inner::before
}
@media screen and (max-width: 511px){
.sidebar-menu{
margin-top:64px;
margin-top:160px;
}
}
@media screen and (max-width: 771px) and (min-width: 512px){
.sidebar-menu {
margin-top:14px
margin-top:160px
}
}
@media screen and (max-width: 1098px) and (min-width: 772px){
.sidebar-menu {
margin-top:51px
margin-top:98px
}
}

View file

@ -395,7 +395,7 @@ return [
'end_date' => 'Enddatum',
'alt_uploaded_image_thumbnail' => 'Hochgeladene Miniaturansicht',
'placeholder_kit' => 'Kit auswählen',
'file_not_found' => 'File not found',
'file_not_found' => 'File not found on server',
'preview_not_available' => '(no preview)',
'setup' => 'Setup',
'pre_flight' => 'Pre-Flight',

View file

@ -403,6 +403,8 @@ return [
'toggle_navigation' => 'Toggle navigation',
'alerts' => 'Alerts',
'tasks_view_all' => 'View all tasks',
'true' => 'True',
'false' => 'False',

View file

@ -41,7 +41,7 @@
<thead>
<tr>
<th data-switchable="true" data-sortable="false" data-field="id" data-visible="false">{{ trans('general.id') }}</th>
<th data-switchable="true" data-sortable="true" data-field="id" data-visible="false">{{ trans('general.id') }}</th>
<th data-switchable="true" data-sortable="true" data-field="name" data-formatter="groupsAdminLinkFormatter" data-visible="true">{{ trans('admin/groups/table.name') }}</th>
<th data-switchable="true" data-sortable="true" data-field="users_count" data-visible="true">{{ trans('admin/groups/table.users') }}</th>
<th data-switchable="true" data-sortable="true" data-field="created_at" data-visible="true" data-formatter="dateDisplayFormatter">{{ trans('general.created_at') }}</th>

View file

@ -152,6 +152,7 @@
<br>
@include ('partials.forms.edit.order_number')
@include ('partials.forms.edit.purchase_date')
@include ('partials.forms.edit.eol_date')
@include ('partials.forms.edit.supplier-select', ['translated_name' => trans('general.supplier'), 'fieldname' => 'supplier_id'])
@php

View file

@ -673,7 +673,8 @@
</div>
</div>
@endif
@if ($asset->asset_eol_date)
<div class="row">
<div class="col-md-2">
<strong>
@ -681,10 +682,10 @@
</strong>
</div>
<div class="col-md-6">
@if ($asset->purchase_date)
{{ Helper::getFormattedDateObject($asset->present()->eol_date(), 'date', false) }}
@if ($asset->asset_eol_date)
{{ Helper::getFormattedDateObject($asset->asset_eol_date, 'date', false) }}
-
{{ Carbon::parse($asset->present()->eol_date())->diffForHumans(['parts' => 2]) }}
{{ Carbon::parse($asset->asset_eol_date)->diffForHumans(['parts' => 2]) }}
@else
{{ trans('general.na_no_purchase_date') }}
@endif

View file

@ -65,50 +65,3 @@
@include ('partials.forms.edit.image-upload')
@stop
@if (!$item->id)
@section('moar_scripts')
<script nonce="{{ csrf_token() }}">
var $eventSelect = $(".parent");
$eventSelect.on("change", function () { parent_details($eventSelect.val()); });
$(function() {
var parent_loc = $(".parent option:selected").val();
if(parent_loc!=''){
parent_details(parent_loc);
}
});
function parent_details(id) {
if (id) {
//start ajax request
$.ajax({
type: 'GET',
url: "{{url('/') }}/api/locations/"+id+"/check",
//force to handle it as text
dataType: "text",
success: function(data) {
var json = $.parseJSON(data);
$("#city").val(json.city);
$("#address").val(json.address);
$("#address2").val(json.address2);
$("#state").val(json.state);
$("#zip").val(json.zip);
$(".country").select2("val",json.country);
}
});
} else {
$("#city").val('');
$("#address").val('');
$("#address2").val('');
$("#state").val('');
$("#zip").val('');
$(".country").select2("val",'');
}
};
</script>
@stop
@endif

View file

@ -10,7 +10,7 @@
@php
$checkin = Helper::getFormattedDateObject($asset->expected_checkin, 'date');
@endphp
| [{{ $asset->present()->name }}]({{ route('hardware.show', ['hardware' => $asset->id]) }}) | [{{ $asset->assigned->present()->fullName }}]({{ route('users.show', ['user'=>$asset->assigned->id]) }}) | {{ $checkin['formatted'] }}
| [{{ $asset->present()->name }}]({{ route('hardware.show', ['hardware' => $asset->id]) }}) | [{{ $asset->assigned->present()->fullName }}]({{ route($asset->targetShowRoute().'.show', [$asset->assigned->id]) }}) | {{ $checkin['formatted'] }}
@endforeach
@endcomponent

View file

@ -570,9 +570,9 @@
function trueFalseFormatter(value) {
if ((value) && ((value == 'true') || (value == '1'))) {
return '<i class="fas fa-check text-success"></i>';
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>';
return '<i class="fas fa-times text-danger"></i><span class="sr-only">{{ trans('general.false') }}</span>';
}
}

View file

@ -3,7 +3,7 @@
{{ Form::label($fieldname, $translated_name, array('class' => 'col-md-3 control-label')) }}
<div class="input-group col-md-4">
<div class="input-group date" data-provide="datepicker" data-date-clear-btn="true" data-date-format="yyyy-mm-dd" data-autoclose="true">
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="{{ $fieldname }}" id="{{ $fieldname }}" value="{{ old($fieldname, ($item->{$fieldname}) ? $item->{$fieldname}->format('Y-m-d') : '') }}" readonly style="background-color:inherit">
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="{{ $fieldname }}" id="{{ $fieldname }}" value="{{ old($fieldname, ($item->{$fieldname}) ? date('Y-m-d', strtotime($item->{$fieldname})) : '') }}" readonly style="background-color:inherit">
<span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span>
</div>
{!! $errors->first($fieldname, '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}

View file

@ -0,0 +1,11 @@
<!-- Purchase Date -->
<div class="form-group {{ $errors->has('asset_eol_date') ? ' has-error' : '' }}">
<label for="asset_eol_date" class="col-md-3 control-label">{{ trans('admin/hardware/form.eol_date') }}</label>
<div class="input-group col-md-4">
<div class="input-group date" data-provide="datepicker" data-date-clear-btn="true" data-date-format="yyyy-mm-dd" data-autoclose="true">
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="asset_eol_date" id="asset_eol_date" readonly value="{{ old('asset_eol_date', $item->asset_eol_date ?? $item->present()->eol_date() ?? '') }}" style="background-color:inherit">
<span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span>
</div>
{!! $errors->first('asset_eol_date', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>

View file

@ -35,7 +35,7 @@
<thead>
<tr>
<th class="col-sm-1" data-field="company">{{ trans('admin/companies/table.title') }}</th>
<th class="col-sm-1" data-field="company.name">{{ trans('admin/companies/table.title') }}</th>
<th class="col-sm-1" data-field="name">{{ trans('admin/accessories/table.title') }}</th>
<th class="col-sm-1" data-field="model_number">{{ trans('general.model_no') }}</th>
<th class="col-sm-1" data-field="qty">{{ trans('admin/accessories/general.total') }}</th>

View file

@ -40,22 +40,36 @@ Route::group(['middleware' => 'auth'], function () {
'parameters' => ['category' => 'category_id'],
]);
/*
* Locations
*/
* Locations
*/
Route::group(['prefix' => 'locations', 'middleware' => ['auth']], function () {
Route::get('{locationId}/clone',
[LocationsController::class, 'getClone']
)->name('clone/license');
Route::get(
'{locationId}/printassigned',
[LocationsController::class, 'print_assigned']
)->name('locations.print_assigned');
Route::get(
'{locationId}/printallassigned',
[LocationsController::class, 'print_all_assigned']
)->name('locations.print_all_assigned');
});
Route::resource('locations', LocationsController::class, [
'parameters' => ['location' => 'location_id'],
]);
Route::get(
'locations/{locationId}/printassigned',
[LocationsController::class, 'print_assigned']
)->name('locations.print_assigned');
Route::get(
'locations/{locationId}/printallassigned',
[LocationsController::class, 'print_all_assigned']
)->name('locations.print_all_assigned');
/*
* Manufacturers

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff