Compare commits

...

68 Commits

Author SHA1 Message Date
snipe fbf069d9a4 Use column sort in numeric DB sorting 2026-03-12 15:42:55 +00:00
snipe 0d257d956f Undo json encode 2026-03-12 14:54:18 +00:00
snipe 4c05f26940 Merge pull request #18681 from grokability/redirect-fixes
Use intended() for redirect options
2026-03-12 14:44:38 +00:00
snipe ce18ff669c Added admin check 2026-03-12 14:42:36 +00:00
snipe a3b5346773 Ignore the sqlite database in git 2026-03-12 14:24:59 +00:00
snipe 3c96491295 Remove unused route 2026-03-12 14:24:46 +00:00
snipe 53abf8cdcc Load count with RMB controller 2026-03-12 14:10:43 +00:00
snipe e376492128 Use intended() for redirect options 2026-03-12 13:57:50 +00:00
snipe 2658b9b064 Fixed variable in trans_choice for deployable check 2026-03-12 13:47:23 +00:00
snipe f412b56caa Fixed #18678 - small UI tweaks 2026-03-12 13:40:47 +00:00
snipe 9c63b40a5a Merge pull request #18680 from grokability/copilot
Added copilot instructions file
2026-03-12 13:21:38 +00:00
snipe 40843f93dc Added copilot instructions file 2026-03-12 13:20:37 +00:00
snipe 9165f59dcc Normalized requiered colors 2026-03-12 12:23:20 +00:00
snipe 92ff333778 Force foreground color for label form-control 2026-03-12 12:13:59 +00:00
snipe 63e62cde1b Moved gates higher, switch to RMB for accessories 2026-03-12 12:13:38 +00:00
snipe c5081ce3e5 Added colors to setting seeder 2026-03-12 11:47:04 +00:00
snipe 67d2a5d094 Use better maintenance name 2026-03-12 11:44:40 +00:00
snipe a170da5c01 Merge pull request #18679 from grokability/normalize-breadcrumb-text
Normalize breadcrumb text
2026-03-12 11:42:27 +00:00
snipe 9652cb312a Normalize breadcrumb text 2026-03-12 11:34:38 +00:00
snipe e4d7e08902 Merge pull request #18672 from marcusmoore/remove-laravel-collective-dep
Fixed #17199: Remove Laravel Collective HTML dependency
2026-03-11 19:53:25 +00:00
snipe 428095b71b Fixed #18670 - set nav link color override in ResetDemo console command 2026-03-11 17:56:58 +00:00
Marcus Moore 411ffb12ca Merge branch 'develop' into remove-laravel-collective-dep 2026-03-11 10:41:06 -07:00
snipe 3b93193da1 Merge pull request #18667 from marcusmoore/migrate-link-methods
Fixed #18666: Migrate Laravel Collective helper methods
2026-03-11 10:14:31 +00:00
snipe 224a813f25 Fixed #18668 - changed button type 2026-03-11 09:33:03 +00:00
Marcus Moore 7d079f74a1 Uninstall laravelcollective/html 2026-03-10 16:52:42 -07:00
Marcus Moore 4ca53e6f70 Remove Collective provider and aliases 2026-03-10 16:45:48 -07:00
Marcus Moore 70d1ffe294 Remove MacroServiceProvider and macros.php 2026-03-10 16:39:30 -07:00
Marcus Moore 335e1a7e18 Merge branch 'develop' into migrate-link-methods 2026-03-10 16:35:23 -07:00
Marcus Moore 287481a44e Fix model reference 2026-03-10 13:38:14 -07:00
Marcus Moore 2dd09f9702 Remove unused method 2026-03-10 13:35:25 -07:00
snipe 9317d6551d Fixed #18653 - “select company” to “company” in user edit 🙄 2026-03-10 20:25:53 +00:00
snipe ed3d30e343 Merge pull request #18657 from marcusmoore/form-macros
Fixed #17200 and #17201: Remove alt_barcode_types and barcode_types macros
2026-03-10 20:11:01 +00:00
Marcus Moore ca5a25f703 Replace remaining calls to link_to_route in Presenters 2026-03-10 13:06:46 -07:00
Marcus Moore 692a9ebebf Replace call to link_to_route 2026-03-10 11:58:27 -07:00
Marcus Moore bf314a0f84 Replace call to link_to_route 2026-03-10 11:54:29 -07:00
Marcus Moore c8c2bb6709 Remove unused serialUrl method from LicensePresenter 2026-03-10 11:31:07 -07:00
Marcus Moore 3fc8b976fc Merge branch 'develop' into form-macros
# Conflicts:
#	resources/macros/macros.php
2026-03-10 10:12:31 -07:00
snipe 6b9dc97fa1 Merge pull request #18665 from grokability/#18662-fix-seat-search
Fixed #18662 wire up search box in assigned license seats
2026-03-10 16:10:37 +00:00
snipe 4f3a30261e Fixed #18661 - return true/false in JSON 2026-03-10 15:42:35 +00:00
snipe e7c478318c Fixed donked route 2026-03-10 15:39:29 +00:00
snipe e75860c6ee Fixed #18662 wire up search box in assigned license seats 2026-03-10 15:31:54 +00:00
snipe d0dbd1e561 Link parent company 2026-03-10 11:40:03 +00:00
snipe e7eb4f0e80 More display_name 2026-03-10 10:25:01 +00:00
snipe 676a995889 Use update check for files controller api 2026-03-10 10:22:39 +00:00
snipe a44fe14de1 Use display_name in more places 2026-03-10 10:14:27 +00:00
snipe 0015dbcd1d Merge pull request #18656 from marcusmoore/form-macro-username-select
Fixed #17208: Replace username_format macro
2026-03-10 09:42:15 +00:00
snipe fc5e7cccbc Merge pull request #18652 from grokability/dependabot/github_actions/develop/docker/login-action-4
Bump docker/login-action from 3 to 4
2026-03-10 09:41:54 +00:00
dependabot[bot] 8987f3f951 Bump docker/login-action from 3 to 4
Bumps [docker/login-action](https://github.com/docker/login-action) from 3 to 4.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 09:30:14 +00:00
snipe ba671a8f1f Merge pull request #18651 from grokability/dependabot/github_actions/develop/docker/build-push-action-7
Bump docker/build-push-action from 6 to 7
2026-03-10 09:29:32 +00:00
snipe fbe871f8d1 Merge pull request #18650 from grokability/dependabot/github_actions/develop/docker/metadata-action-6
Bump docker/metadata-action from 5 to 6
2026-03-10 09:29:10 +00:00
snipe 116b2d1229 Merge pull request #18649 from grokability/dependabot/github_actions/develop/docker/setup-buildx-action-4
Bump docker/setup-buildx-action from 3 to 4
2026-03-10 09:28:03 +00:00
snipe 20fd870b59 Merge pull request #18658 from marcusmoore/form-macro-countries
Fixed #17202: Replaced countries form macro
2026-03-10 09:27:05 +00:00
snipe 5c46990195 Check for user on enable_sounds 2026-03-10 09:20:35 +00:00
snipe fab57020f2 Prevent browser errors since input field is display none 2026-03-10 09:16:24 +00:00
snipe b37074f473 Null check on status (RB-4087) 2026-03-10 09:03:57 +00:00
snipe 24e2e81a28 Use component table in suppliers 2026-03-10 09:00:29 +00:00
Marcus Moore ccabc1fbcc Remove countries macro 2026-03-09 17:37:58 -07:00
Marcus Moore f847f83cb8 Replace macro in location modal 2026-03-09 17:36:26 -07:00
Marcus Moore e0771827aa Replace country in address partial 2026-03-09 17:34:57 -07:00
Marcus Moore fa6adaa155 Migrate countries macro on user page 2026-03-09 17:22:43 -07:00
Marcus Moore f3504ce6fc Remove barcode_types macro 2026-03-09 16:36:54 -07:00
Marcus Moore a075ca904b Remove alt_barcode_types macro 2026-03-09 16:36:26 -07:00
Marcus Moore e3fb6fabf8 Remove username_format maco 2026-03-09 16:30:12 -07:00
Marcus Moore 6f89af790e Migrate username format to blade component 2026-03-09 16:29:55 -07:00
snipe 28f493d84d Escape pivot notes 2026-03-09 09:06:58 +00:00
dependabot[bot] a87e862148 Bump docker/build-push-action from 6 to 7
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6 to 7.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:42:34 +00:00
dependabot[bot] 6e264bfee0 Bump docker/metadata-action from 5 to 6
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5 to 6.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:42:27 +00:00
dependabot[bot] 1ecf862f2d Bump docker/setup-buildx-action from 3 to 4
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:42:22 +00:00
74 changed files with 480 additions and 491 deletions
+121
View File
@@ -0,0 +1,121 @@
# GitHub Copilot Custom Instructions for Snipe-IT
These instructions guide Copilot to generate code that aligns with modern Laravel 11 standards, PHP 8.2/8.4 features, software engineering principles, and industry best practices to improve software quality, maintainability, and security.
## ✅ General Coding Standards
- Prefer short, expressive, and readable code.
- Use **meaningful, descriptive variable, function, class, and file names**.
- Apply proper PHPDoc blocks for classes, methods, and complex logic.
- Organize code into small, reusable functions or classes with single responsibility.
- Avoid magic numbers or hard-coded strings; use constants or config files.
## ✅ PHP 8.2/8.4 Best Practices
- Use **readonly properties** to enforce immutability where applicable.
- Use **Enums** instead of string or integer constants.
- Utilize **First-class callable syntax** for callbacks.
- Leverage **Constructor Property Promotion**.
- Use **Union Types**, **Intersection Types**, and **true/false return types** for strict typing.
- Apply **Static Return Type** where needed.
- Use the **Nullsafe Operator (?->)** for optional chaining.
- Adopt **final classes** where extension is not intended.
- Use **Named Arguments** for improved clarity when calling functions with multiple parameters.
## ✅ Laravel 11 Project Structure & Conventions
- Follow the official Laravel project structure:
- `app/Http/Controllers` - Controllers
- `app/Models` - Eloquent models
- `app/Http/Requests` - Form request validation
- `app/Http/Resources` - API resource responses
- `app/Enums` - Enums
- `app/Services` - Business logic
- `app/Data` - Data Transfer Objects (DTOs)
- `app/Actions` - Single-responsibility action classes
- `app/Policies` - Authorization logic
- Controllers must:
- Be thin.
- Use dependency injection.
- Use Form Requests for validation.
- Return typed responses (e.g., `JsonResponse`).
- Use Resource classes for API responses.
## ✅ Eloquent ORM & Database
- Use **Eloquent Models** with proper `$fillable` or `$guarded` attributes for mass assignment protection.
- Utilize **casts** for date, boolean, JSON, and custom data types.
- Apply **accessors & mutators** for attribute transformation.
- Avoid direct raw SQL unless absolutely necessary; prefer Eloquent or Query Builder.
- Migrations:
- Always use migrations for schema changes.
- Include proper constraints (foreign keys, unique indexes, etc.).
- Prefer UUIDs or ULIDs as primary keys where applicable.
## ✅ API Development
- Use **API Resource classes** for consistent and structured JSON responses.
- Apply **route model binding** where possible.
- Use Form Requests for input validation.
## ✅ Blade & Frontend (if applicable)
- Keep Blade templates clean and logic-free; use View Composers or dedicated View Models for complex data.
- Use `@props`, `@aware`, `@once` Blade features appropriately.
- Utilize Alpine.js or Livewire for interactive frontend logic (optional).
## ✅ Security Best Practices
- Never trust user input; always validate and sanitize inputs.
- Use prepared statements via Eloquent or Query Builder to prevent SQL injection.
- Use Laravel's built-in CSRF, XSS, and validation mechanisms.
- Store sensitive information in `.env`, never hard-code secrets.
- Apply proper authorization checks using Policies or Gates.
- Follow principle of least privilege for users, roles, and permissions.
## ✅ Testing Standards
- Use **factories** for test data setup.
- Include feature tests for user-facing functionality.
- Include unit tests for business logic, services, and helper classes.
- Mock external services using Laravel's `Http::fake()` or equivalent.
- Maintain high code coverage but focus on meaningful tests over 100% coverage obsession.
## ✅ Software Quality & Maintainability
- Follow **SOLID Principles**:
- Single Responsibility Principle (SRP)
- Open/Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
- Follow **DRY** (Don't Repeat Yourself) and **KISS** (Keep It Simple, Stupid) principles.
- Apply **YAGNI** (You Aren't Gonna Need It) to avoid overengineering.
- Document complex logic with PHPDoc and inline comments.
## ✅ Performance & Optimization
- Eager load relationships to avoid N+1 queries.
- Use caching with Laravel's Cache system for frequently accessed data.
- Paginate large datasets using `paginate()` instead of `get()`.
- Queue long-running tasks using Laravel Queues.
- Optimize database indexes for common queries.
## ✅ Modern Laravel Features to Use
- Use **Event Broadcasting** if real-time updates are needed.
- Use **Full-text search** if search functionality is required.
- Use **Rate Limiting** for API routes.
## ✅ Additional Copilot Behavior Preferences
- Generate **strictly typed**, modern PHP code using latest language features.
- Prioritize **readable, clean, maintainable** code over cleverness.
- Avoid legacy or deprecated Laravel patterns (facade overuse, logic-heavy views, etc.).
- Suggest proper class placement based on Laravel directory structure.
- Suggest tests alongside new features where applicable.
- Default to **immutability**, **dependency injection**, and **encapsulation** best practices.
No newline at end of file
+4 -4
View File
@@ -46,13 +46,13 @@ jobs:
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
@@ -64,7 +64,7 @@ jobs:
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
id: meta_build
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: snipe/snipe-it
tags: ${{ env.IMAGE_TAGS }}
@@ -73,7 +73,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile.alpine
+4 -4
View File
@@ -46,13 +46,13 @@ jobs:
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
@@ -64,7 +64,7 @@ jobs:
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'snipe-it' image
id: meta_build
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: snipe/snipe-it
tags: ${{ env.IMAGE_TAGS }}
@@ -73,7 +73,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push 'snipe-it' image
id: docker_build
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
@@ -52,6 +52,7 @@ class ResetDemoSettings extends Command
$settings->header_color = '#3c8dbc';
$settings->link_dark_color = '#5fa4cc';
$settings->link_light_color = '#296282;';
$settings->nav_link_color = '#FFFFFF';
$settings->label2_2d_type = 'QRCODE';
$settings->default_currency = 'USD';
$settings->brand = 2;
+9 -8
View File
@@ -1547,18 +1547,19 @@ class Helper
]) ? 'rtl' : 'ltr';
}
static public function getRedirectOption($request, $id, $table, $item_id = null) : RedirectResponse
{
$redirect_option = Session::get('redirect_option') ?? $request->redirect_option;
$checkout_to_type = Session::get('checkout_to_type') ?? null;
$checkedInFrom = Session::get('checkedInFrom');
$other_redirect = Session::get('other_redirect');
$backUrl = Session::pull('back_url', route('home'));
$redirect_option = session('redirect_option') ?? $request->redirect_option;
$checkout_to_type = session('checkout_to_type') ?? null;
$checkedInFrom = session('checkedInFrom');
$other_redirect = session('other_redirect');
$backUrl = session()->pull('url.intended', 'home');
// return to previous page
if ($redirect_option === 'back') {
return redirect()->to($backUrl);
if ($redirect_option == 'back') {
return redirect()->intended($backUrl);
}
// return to index
@@ -114,7 +114,8 @@ class AccessoriesController extends Controller
*/
public function edit(Accessory $accessory) : View | RedirectResponse
{
$this->authorize('update', Accessory::class);
$this->authorize('update', $accessory);
session()->put('url.intended', url()->previous());
return view('accessories.edit')->with('item', $accessory)->with('category_type', 'accessory');
}
@@ -128,7 +129,7 @@ class AccessoriesController extends Controller
public function getClone(Accessory $accessory) : View | RedirectResponse
{
$this->authorize('create', Accessory::class);
$this->authorize('create', $accessory);
$cloned = clone $accessory;
$accessory_to_clone = $accessory;
$cloned->id = null;
@@ -149,9 +150,9 @@ class AccessoriesController extends Controller
*/
public function update(ImageUploadRequest $request, Accessory $accessory) : RedirectResponse
{
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessory->id)) {
$this->authorize('update', $accessory);
$this->authorize($accessory);
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessory->id)) {
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$accessory->checkouts_count"
@@ -163,8 +164,6 @@ class AccessoriesController extends Controller
->withInput();
}
// Update the accessory data
$accessory->name = request('name');
$accessory->location_id = request('location_id');
@@ -182,7 +181,7 @@ class AccessoriesController extends Controller
$accessory = $request->handleImages($accessory);
if($request->input('redirect_option') === 'back'){
if ($request->input('redirect_option') === 'back'){
session()->put(['redirect_option' => 'index']);
} else {
session()->put(['redirect_option' => $request->input('redirect_option')]);
@@ -205,30 +204,26 @@ class AccessoriesController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $accessoryId
*/
public function destroy($accessoryId) : RedirectResponse
public function destroy(Accessory $accessory) : RedirectResponse
{
if (is_null($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
}
$this->authorize('delete', $accessory);
$accessory->loadCount('checkouts as checkouts_count');
$this->authorize($accessory);
if ($accessory->checkouts_count > 0) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/general.delete_disabled'));
}
if ($accessory->image) {
try {
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
} catch (\Exception $e) {
Log::debug($e);
if ($accessory->isDeletable()) {
if ($accessory->image) {
try {
Storage::disk('public')->delete('accessories'.'/'.$accessory->image);
} catch (\Exception $e) {
Log::debug($e);
}
}
$accessory->delete();
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.delete.success'));
}
$accessory->delete();
return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.delete.success'));
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/general.delete_disabled'));
}
@@ -243,11 +238,9 @@ class AccessoriesController extends Controller
*/
public function show(Accessory $accessory) : View | RedirectResponse
{
$accessory->loadCount('checkouts as checkouts_count');
$accessory->load(['adminuser' => fn($query) => $query->withTrashed()]);
$this->authorize('view', $accessory);
$accessory->loadCount('checkouts as checkouts_count');
$accessory->load(['adminuser' => fn($query) => $query->withTrashed()]);
return view('accessories.view', compact('accessory'));
}
}
@@ -29,6 +29,7 @@ class AccessoryCheckinController extends Controller
}
$accessory = Accessory::find($accessory_user->accessory_id);
$this->authorize('checkin', $accessory);
//based on what the accessory is checked out to the target redirect option will be displayed accordingly.
$target_option = match ($accessory_user->assigned_type) {
@@ -36,7 +37,7 @@ class AccessoryCheckinController extends Controller
'App\Models\Location' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.location')]),
default => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.user')]),
};
$this->authorize('checkin', $accessory);
return view('accessories/checkin', compact('accessory', 'target_option'))->with('backto', $backto);
@@ -57,6 +58,7 @@ class AccessoryCheckinController extends Controller
}
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
session()->put('checkedInFrom', $accessory_checkout->assigned_to);
session()->put('checkout_to_type', match ($accessory_checkout->assigned_type) {
@@ -65,7 +67,7 @@ class AccessoryCheckinController extends Controller
'App\Models\Asset' => 'asset',
});
$this->authorize('checkin', $accessory);
$checkin_hours = date('H:i:s');
$checkin_at = date('Y-m-d H:i:s');
if ($request->filled('checkin_at')) {
@@ -27,31 +27,24 @@ class AccessoryCheckoutController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $id
*/
public function create($id) : View | RedirectResponse
public function create(Accessory $accessory) : View | RedirectResponse
{
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($id)) {
$this->authorize('checkout', $accessory);
$this->authorize('checkout', $accessory);
if ($accessory->category) {
// Make sure there is at least one available to checkout
if ($accessory->numRemaining() <= 0){
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
}
// Return the checkout view
return view('accessories/checkout', compact('accessory'));
if ($accessory->category) {
// Make sure there is at least one available to checkout
if ($accessory->numRemaining() <= 0){
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkout.unavailable'));
}
// Invalid category
return redirect()->route('accessories.edit', ['accessory' => $accessory->id])
->with('error', trans('general.invalid_item_category_single', ['type' => trans('general.accessory')]));
// Return the checkout view
return view('accessories/checkout', compact('accessory'));
}
// Not found
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
// Invalid category
return redirect()->route('accessories.edit', ['accessory' => $accessory->id])
->with('error', trans('general.invalid_item_category_single', ['type' => trans('general.accessory')]));
}
@@ -397,7 +397,7 @@ class AssetsController extends Controller
// This handles all of the pivot sorting (versus the assets.* fields
// in the allowed_columns array)
$column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.created_at';
$column_sort = in_array($sort_override, $allowed_columns) ? 'assets.'.$sort_override : 'assets.created_at';
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -453,7 +453,7 @@ class AssetsController extends Controller
// This may not work for all databases, but it works for MySQL
if ($numeric_sort) {
$assets->orderByRaw(DB::getTablePrefix() . 'assets.' . $sort_override . ' * 1 ' . $order);
$assets->orderByRaw(DB::getTablePrefix() . $column_sort . ' * 1 ' . $order);
} else {
$assets->orderBy($sort_override, $order);
}
@@ -1149,7 +1149,7 @@ class AssetsController extends Controller
'id' => $asset->id,
'asset_tag' => $asset->asset_tag,
'note' => e($request->input('note')),
'status_label' => e($asset->assetstatus->display_name),
'status_label' => e($asset->assetstatus?->display_name),
'status_type' => $asset->assetstatus->getStatuslabelType(),
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date),
];
@@ -37,6 +37,9 @@ class LicenseSeatsController extends Controller
$seats->ByAssigned();
}
if ($request->filled('search')) {
$seats->TextSearch($request->input('search'));
}
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
@@ -93,7 +93,7 @@ class UploadedFilesController extends Controller
// Check the permissions to make sure the user can view the object
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
$this->authorize('view', $object);
$this->authorize('update', $object);
if (!$object) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_upload_status.invalid_object')));
@@ -312,7 +312,7 @@ class AssetsController extends Controller
public function edit(Asset $asset) : View | RedirectResponse
{
$this->authorize($asset);
session()->put('back_url', url()->previous());
session()->put('url.intended', url()->previous());
return view('hardware/edit')
->with('item', $asset)
->with('statuslabel_list', Helper::statusLabelList())
@@ -508,16 +508,9 @@ class AssetsController extends Controller
* @param int $assetId
* @since [v1.0]
*/
public function destroy(Request $request, $assetId) : RedirectResponse
public function destroy(Request $request, Asset $asset) : RedirectResponse
{
// Check if the asset exists
if (is_null($asset = Asset::find($assetId))) {
// Redirect to the asset management page with error
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}
$this->authorize('delete', $asset);
if ($asset->assignedTo) {
$target = $asset->assignedTo;
@@ -117,7 +117,7 @@ class ComponentsController extends Controller
{
$this->authorize('update', $component);
session()->put('back_url', url()->previous());
session()->put('url.intended', url()->previous());
return view('components/edit')
->with('item', $component)
->with('category_type', 'component');
@@ -124,7 +124,7 @@ class ConsumablesController extends Controller
public function edit(Consumable $consumable) : View | RedirectResponse
{
$this->authorize($consumable);
session()->put('back_url', url()->previous());
session()->put('url.intended', url()->previous());
return view('consumables/edit')
->with('item', $consumable)
->with('category_type', 'consumable');
@@ -130,7 +130,7 @@ class LicensesController extends Controller
{
$this->authorize('update', $license);
session()->put('back_url', url()->previous());
session()->put('url.intended', url()->previous());
$maintained_list = [
'' => 'Maintained',
'1' => 'Yes',
+16 -21
View File
@@ -326,31 +326,26 @@ class LocationsController extends Controller
* @since [v1.0]
* @param int $id
*/
public function postRestore($id) : RedirectResponse
public function postRestore(Location $location) : RedirectResponse
{
$this->authorize('create', Location::class);
$this->authorize('delete', $location);
if ($location = Location::withTrashed()->find($id)) {
if ($location->deleted_at == '') {
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.location')]));
}
if ($location->restore()) {
$logaction = new Actionlog();
$logaction->item_type = Location::class;
$logaction->item_id = $location->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
}
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()]));
if ($location->deleted_at == '') {
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.location')]));
}
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
if ($location->restore()) {
$logaction = new Actionlog();
$logaction->item_type = Location::class;
$logaction->item_id = $location->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
}
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()]));
}
+2 -2
View File
@@ -191,9 +191,9 @@ class SettingsController extends Controller
$request->validate(['site_name' => 'required']);
}
$setting->header_color = $request->input('header_color');
$setting->header_color = $request->input('header_color', '#3c8dbc');
$setting->link_light_color = $request->input('link_light_color', '#296282');
$setting->link_dark_color = $request->input('link_dark_color', '#296282');
$setting->link_dark_color = $request->input('link_dark_color', '#5fa4cc');
$setting->nav_link_color = $request->input('nav_link_color', '#FFFFFF');
$setting->site_name = $request->input('site_name', 'Snipe-IT');
+43 -33
View File
@@ -203,8 +203,8 @@ class UsersController extends Controller
public function edit(User $user)
{
$this->authorize('update', User::class);
session()->put('back_url', url()->previous());
$this->authorize('update', $user);
session()->put('url.intended', url()->previous());
$user = User::with(['assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc'])->withTrashed()->find($user->id);
if ($user) {
@@ -238,7 +238,7 @@ class UsersController extends Controller
*/
public function update(SaveUserRequest $request, User $user)
{
$this->authorize('update', User::class);
$this->authorize('update', $user);
// This is a janky hack to prevent people from changing admin demo user data on the public demo.
// The $ids 1 and 2 are special since they are seeded as superadmins in the demo seeder.
@@ -259,12 +259,19 @@ class UsersController extends Controller
// Figure out of this user was an admin before this edit
$orig_permissions_array = $user->decodePermissions();
$orig_superuser = '0';
$orig_admin = '0';
if (is_array($orig_permissions_array)) {
if (array_key_exists('superuser', $orig_permissions_array)) {
$orig_superuser = $orig_permissions_array['superuser'];
}
}
if (is_array($orig_permissions_array)) {
if (array_key_exists('admin', $orig_permissions_array)) {
$orig_admin = $orig_permissions_array['admin'];
}
}
// Update the user fields
@@ -323,6 +330,11 @@ class UsersController extends Controller
$permissions_array['superuser'] = $orig_superuser;
}
if ((! auth()->user()->isSuperUser()) && (! auth()->user()->isAdmin())) {
unset($permissions_array['admin']);
$permissions_array['admin'] = $orig_admin;
}
$user->permissions = json_encode($permissions_array);
// Only save groups if the user is a superuser
@@ -387,37 +399,35 @@ class UsersController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function getRestore($id = null)
public function getRestore(User $user)
{
if ($user = User::withTrashed()->find($id)) {
$this->authorize('delete', $user);
if ($user->deleted_at == '') {
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.user')]));
}
$this->authorize('delete', $user);
if ($user->restore()) {
$logaction = new Actionlog();
$logaction->item_type = User::class;
$logaction->item_id = $user->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index
$deleted_users = User::onlyTrashed()->count();
if ($deleted_users > 0) {
return redirect()->back()->with('success', trans('admin/users/message.success.restored'));
}
return redirect()->route('users.index')->with('success', trans('admin/users/message.success.restored'));
}
// Check validation to make sure we're not restoring a user with the same username as an existing user
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.user'), 'error' => $user->getErrors()->first()]));
if ($user->deleted_at == '') {
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.user')]));
}
return redirect()->route('users.index')->with('error', trans('admin/users/message.does_not_exist'));
if ($user->restore()) {
$logaction = new Actionlog();
$logaction->item_type = User::class;
$logaction->item_id = $user->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index
$deleted_users = User::onlyTrashed()->count();
if ($deleted_users > 0) {
return redirect()->back()->with('success', trans('admin/users/message.success.restored'));
}
return redirect()->route('users.index')->with('success', trans('admin/users/message.success.restored'));
}
// Check validation to make sure we're not restoring a user with the same username as an existing user
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.user'), 'error' => $user->getErrors()->first()]));
}
/**
@@ -432,7 +442,7 @@ class UsersController extends Controller
public function show(User $user)
{
// Make sure the user can view users at all
$this->authorize('view', User::class);
$this->authorize('view', $user);
$user = User::with([
'consumables',
@@ -465,7 +475,7 @@ class UsersController extends Controller
*/
public function getClone(Request $request, User $user)
{
$this->authorize('create', User::class);
$this->authorize('create', $user);
// We need to reverse the UI specific logic for our
// permissions here before we update the user.
@@ -634,9 +644,9 @@ class UsersController extends Controller
* @since [v1.8]
* @author Aladin Alaily
*/
public function printInventory($id)
public function printInventory(User $user, $id)
{
$this->authorize('view', User::class);
$this->authorize('view', $user);
$user = User::where('id', $id)
->with([
@@ -111,11 +111,11 @@ class AssetModelsTransformer
$array = [
'id' => (int) $file->id,
'filename' => e($file->filename),
'note' => $file->note,
'note' => $file->note ? e($file->note) : null,
'url' => route('show/modelfile', [$assetmodel->id, $file->id]),
'created_by' => ($file->adminuser) ? [
'id' => (int) $file->adminuser->id,
'name'=> e($file->adminuser->present()->fullName),
'name'=> e($file->adminuser->display_name),
] : null,
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($file->updated_at, 'datetime'),
+2 -2
View File
@@ -322,14 +322,14 @@ class AssetsTransformer
'id' => $accessory_checkout->id,
'accessory' => [
'id' => $accessory_checkout->accessory->id,
'name' => $accessory_checkout->accessory->name,
'name' => e($accessory_checkout->accessory->display_name),
],
'assigned_to' => $accessory_checkout->assigned_to,
'image' => ($accessory_checkout->accessory->image) ? Storage::disk('public')->url('accessories/' . e($accessory_checkout->accessory->image)) : null,
'note' => $accessory_checkout->note ? e($accessory_checkout->note) : null,
'created_by' => $accessory_checkout->adminuser ? [
'id' => (int)$accessory_checkout->adminuser->id,
'name' => e($accessory_checkout->adminuser->present()->fullName),
'name' => e($accessory_checkout->display_name),
] : null,
'created_at' => Helper::getFormattedDateObject($accessory_checkout->created_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($accessory_checkout->deleted_at, 'datetime'),
@@ -91,7 +91,7 @@ class ComponentsTransformer
'id' => (int) $asset->id,
'name' => e($asset->model->display_name).' '.e($asset->display_name),
'qty' => $asset->pivot->assigned_qty,
'note' => $asset->pivot->note,
'note' => e($asset->pivot->note),
'type' => 'asset',
'created_at' => Helper::getFormattedDateObject($asset->pivot->created_at, 'datetime'),
'available_actions' => ['checkin' => true],
@@ -44,7 +44,7 @@ class CustomFieldsTransformer
'db_column_name' => e($field->db_column_name()),
'format' => e($field->format),
'field_values' => ($field->field_values) ? e($field->field_values) : null,
'field_encrypted' => $field->field_encrypted,
'field_encrypted' => ($field->field_encrypted =='1') ? true : false,
'field_values_array' => ($field->field_values) ? explode("\r\n", e($field->field_values)) : null,
'type' => e($field->element),
'required' => (($field->pivot) && ($field->pivot->required=='1')) ? true : false,
@@ -30,7 +30,7 @@ class LocationsTransformer
foreach ($location->children as $child) {
$children_arr[] = [
'id' => (int) $child->id,
'name' => $child->name,
'name' => e($child->display_name),
];
}
}
@@ -157,7 +157,7 @@ class LocationsTransformer
'name' => e($location->name),
'created_by' => $location->adminuser ? [
'id' => (int) $location->adminuser->id,
'name'=> e($location->adminuser->present()->fullName),
'name'=> e($location->adminuser->display_name),
]: null,
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
];
@@ -171,7 +171,7 @@ class LocationsTransformer
if ($accessory) {
return [
'id' => $accessory->id,
'name' => $accessory->name,
'name' => e($accessory->display_name),
];
}
@@ -41,7 +41,7 @@ class UploadedFilesTransformer
'note' => ($file->note) ? e($file->note) : null,
'created_by' => ($file->adminuser) ? [
'id' => (int) $file->adminuser->id,
'name'=> e($file->adminuser->present()->fullName),
'name'=> e($file->adminuser->display_name),
] : null,
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
+23 -2
View File
@@ -5,6 +5,7 @@ namespace App\Models;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableChildTrait;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Notifications\CheckinLicenseNotification;
use App\Notifications\CheckoutLicenseNotification;
use App\Presenters\Presentable;
@@ -14,13 +15,15 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class LicenseSeat extends SnipeModel implements ICompanyableChild
{
use Acceptable;
use CompanyableChildTrait;
use HasFactory;
use Loggable;
use Presentable;
use Searchable;
use SoftDeletes;
protected $presenter = \App\Presenters\LicenseSeatPresenter::class;
use Presentable;
protected $guarded = 'id';
protected $table = 'license_seats';
@@ -39,7 +42,25 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
'notes',
];
use Acceptable;
/**
* The attributes that should be included when searching the model.
*
* @var array
*/
protected $searchableAttributes = [
'notes',
];
/**
* The relations and their attributes that should be included when searching the model.
*
* @var array
*/
protected $searchableRelations = [
'user' => ['first_name', 'last_name', 'display_name', 'username', 'email'],
'asset' => ['name', 'asset_tag'],
];
public function getCompanyableParents()
{
+1 -1
View File
@@ -265,7 +265,7 @@ class AccessoryPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Accessory', $this])) {
return (string)link_to_route('accessories.show', e($this->display_name), $this->id);
return '<a href="' . route('accessories.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
-3
View File
@@ -22,9 +22,6 @@ class ActionlogPresenter extends Presenter
public function item()
{
if ($this->action_type == 'uploaded') {
return (string) link_to_route('show/userfile', $this->model->filename, [$this->model->item->id, $this->model->id]);
}
if ($item = $this->model->item) {
if (empty($item->deleted_at)) {
return $this->model->item->present()->nameUrl();
+1 -1
View File
@@ -266,7 +266,7 @@ class AssetModelPresenter extends Presenter
*/
public function nameUrl()
{
return (string) link_to_route('models.show', $this->name, $this->id);
return '<a href="' . route('models.show', $this->id) . '">' . e($this->name) . '</a>';
}
/**
+1 -1
View File
@@ -452,7 +452,7 @@ class AssetPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Asset', $this])) {
return (string)link_to_route('hardware.show', e($this->display_name), $this->id);
return '<a href="' . route('hardware.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -143,7 +143,7 @@ class CategoryPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Category', $this])) {
return (string)link_to_route('categories.show', e($this->display_name), $this->id);
return '<a href="' . route('categories.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -166,7 +166,7 @@ class CompanyPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Company', $this])) {
return (string)link_to_route('companies.show', e($this->display_name), $this->id);
return '<a href="' . route('companies.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -257,7 +257,7 @@ class ComponentPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Component', $this])) {
return (string)link_to_route('components.show', e($this->display_name), $this->id);
return '<a href="' . route('components.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -255,6 +255,6 @@ class ConsumablePresenter extends Presenter
*/
public function nameUrl()
{
return (string) link_to_route('consumables.show', e($this->name), $this->id);
return '<a href="' . route('consumables.show', $this->id) . '">' . e($this->name) . '</a>';
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ class CustomFieldsetPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\CustomFieldset', $this])) {
return (string)link_to_route('fieldsets.show', e($this->display_name), $this->id);
return '<a href="' . route('fieldsets.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+2 -2
View File
@@ -125,8 +125,8 @@ class DepartmentPresenter extends Presenter
*/
public function viewUrl()
{
if (auth()->user()->can('view', ['\App\Models\Location', $this])) {
return (string)link_to_route('locations.show', $this->display_name, $this->id);
if (auth()->user()->can('view', ['\App\Models\Department', $this])) {
return '<a href="' . route('departments.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return $this->display_name;
}
+1 -1
View File
@@ -111,7 +111,7 @@ class DepreciationPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Depreciation', $this])) {
return (string)link_to_route('depreciations.show', e($this->display_name), $this->id);
return '<a href="' . route('depreciations.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
@@ -181,7 +181,7 @@ class DepreciationReportPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Depreciation', $this])) {
return (string)link_to_route('depreciations.show', e($this->display_name), $this->id);
return '<a href="' . route('depreciations.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -10
View File
@@ -323,7 +323,7 @@ class LicensePresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\License', $this])) {
return (string)link_to_route('licenses.show', e($this->display_name), $this->id);
return '<a href="' . route('licenses.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
@@ -339,15 +339,6 @@ class LicensePresenter extends Presenter
return $this->name;
}
/**
* Link to this licenses serial
* @return string
*/
public function serialUrl()
{
return (string) link_to('/licenses/'.$this->id, mb_strimwidth($this->serial, 0, 50, '...'));
}
/**
* Url to view this item.
* @return string
+1 -1
View File
@@ -351,7 +351,7 @@ class LocationPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Location', $this])) {
return (string)link_to_route('locations.show', e($this->display_name), $this->id);
return '<a href="' . route('locations.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -184,7 +184,7 @@ class ManufacturerPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Manufacturer', $this])) {
return (string)link_to_route('manufacturers.show', e($this->display_name), $this->id);
return '<a href="' . route('manufacturers.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -296,7 +296,7 @@ class PredefinedKitPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\PredefinedKit', $this])) {
return (string)link_to_route('kits.show', e($this->display_name), $this->id);
return '<a href="' . route('kits.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+2 -2
View File
@@ -210,7 +210,7 @@ class SupplierPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\Supplier', $this])) {
return (string)link_to_route('suppliers.show', e($this->display_name), $this->id);
return '<a href="' . route('suppliers.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
@@ -232,7 +232,7 @@ class SupplierPresenter extends Presenter
public function viewUrl()
{
if (auth()->user()->can('view', ['\App\Models\Supplier', $this])) {
return (string)link_to_route('suppliers.show', $this->display_name, $this->id);
return '<a href="' . route('suppliers.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+1 -1
View File
@@ -529,7 +529,7 @@ class UserPresenter extends Presenter
public function nameUrl()
{
if (auth()->user()->can('view', ['\App\Models\User', $this])) {
return (string)link_to_route('users.show', $this->display_name, $this->id);
return '<a href="' . route('users.show', $this->id) . '">' . e($this->display_name) . '</a>';
} else {
return e($this->display_name);
}
+37 -23
View File
@@ -80,7 +80,7 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('hardware.edit', fn (Trail $trail, Asset $asset) =>
$trail->parent('hardware.index', route('hardware.index'))
->push($asset->display_name, route('hardware.show', $asset))
->push(trans('admin/hardware/general.edit'))
->push(trans('general.update'))
);
@@ -114,7 +114,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('models.edit', fn (Trail $trail, AssetModel $model) =>
$trail->parent('models.index', route('models.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $model->name]), route('models.edit', $model))
->push($model->display_name, route('models.show', $model))
->push(trans('general.update'))
);
@@ -138,7 +139,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('accessories.edit', fn (Trail $trail, Accessory $accessory) =>
$trail->parent('accessories.index', route('accessories.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $accessory->name]), route('accessories.edit', $accessory))
->push($accessory->display_name, route('accessories.show', $accessory))
->push(trans('general.update'))
);
@@ -162,7 +164,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('categories.edit', fn (Trail $trail, Category $category) =>
$trail->parent('categories.index', route('categories.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $category->name]), route('categories.edit', $category))
->push($category->display_name, route('categories.show', $category))
->push(trans('general.update'))
);
@@ -187,7 +190,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('companies.edit', fn (Trail $trail, Company $company) =>
$trail->parent('companies.index', route('companies.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $company->name]), route('companies.edit', $company))
->push($company->display_name, route('companies.show', $company))
->push(trans('general.update'))
);
@@ -211,7 +215,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('components.edit', fn (Trail $trail, Component $component) =>
$trail->parent('components.index', route('components.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $component->name]), route('components.edit', $component))
->push($component->display_name, route('components.show', $component))
->push(trans('general.update'))
);
Breadcrumbs::for('components.clone.create', fn (Trail $trail, Component $component) =>
@@ -241,7 +246,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('consumables.edit', fn (Trail $trail, Consumable $consumable) =>
$trail->parent('consumables.index', route('consumables.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $consumable->name]), route('consumables.edit', $consumable))
->push($consumable->display_name, route('consumables.show', $consumable))
->push(trans('general.update'))
);
/**
@@ -259,7 +265,7 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('fields.edit', fn (Trail $trail, CustomField $field) =>
$trail->parent('fields.index', route('fields.index'))
->push($field->name, route('fields.edit', $field))
->push(trans('general.update')) // We skip the show section here since there isn't really a concept of fields.show
);
/**
@@ -279,7 +285,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('fieldsets.edit', fn (Trail $trail, CustomFieldset $fieldset) =>
$trail->parent('fields.index', route('fields.index'))
->push($fieldset->name, route('fieldsets.edit', $fieldset))
->push($fieldset->display_name, route('fieldsets.show', $fieldset))
->push(trans('general.update'))
);
/**
@@ -302,7 +309,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('departments.edit', fn (Trail $trail, Department $department) =>
$trail->parent('departments.index', route('departments.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $department->name]), route('departments.edit', $department))
->push($department->display_name, route('departments.show', $department))
->push(trans('general.update'))
);
@@ -326,7 +334,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('depreciations.edit', fn (Trail $trail, Depreciation $depreciation) =>
$trail->parent('depreciations.index', route('depreciations.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $depreciation->name]), route('depreciations.edit', $depreciation))
->push($depreciation->display_name, route('depreciations.show', $depreciation))
->push(trans('general.update'))
);
/**
@@ -349,7 +358,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('groups.edit', fn (Trail $trail, Group $group) =>
$trail->parent('groups.index', route('groups.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $group->name]), route('groups.edit', $group))
->push($group->display_name, route('groups.show', $group))
->push(trans('general.update'))
);
@@ -374,7 +384,6 @@ class BreadcrumbsServiceProvider extends ServiceProvider
);
}
Breadcrumbs::for('licenses.create', fn (Trail $trail) =>
$trail->parent('licenses.index', route('licenses.index'))
->push(trans('general.create'), route('licenses.create'))
@@ -387,7 +396,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('licenses.edit', fn (Trail $trail, License $license) =>
$trail->parent('licenses.index', route('licenses.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $license->name]), route('licenses.edit', $license))
->push($license->display_name, route('licenses.show', $license))
->push(trans('general.update'))
);
@@ -417,8 +427,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('locations.edit', fn (Trail $trail, Location $location) =>
$trail->parent('locations.index', route('locations.index'))
->push($location->name, route('locations.show', $location))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $location->name]), route('locations.edit', $location))
->push($location->display_name, route('locations.show', $location))
->push(trans('general.update'))
);
/**
@@ -441,8 +451,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('maintenances.edit', fn (Trail $trail, Maintenance $maintenance) =>
$trail->parent('maintenances.index', route('maintenances.index'))
->push($maintenance->name, route('maintenances.show', $maintenance))
->push(trans('general.update', ['name' => $maintenance->name]), route('maintenances.edit', $maintenance))
->push($maintenance->display_name, route('maintenances.show', $maintenance))
->push(trans('general.update'))
);
@@ -467,7 +477,7 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('manufacturers.edit', fn (Trail $trail, Manufacturer $manufacturer) =>
$trail->parent('manufacturers.index', route('manufacturers.index'))
->push($manufacturer->name, route('manufacturers.show', $manufacturer))
->push(trans('general.update', ['name' => $manufacturer->name]), route('manufacturers.edit', $manufacturer))
->push(trans('general.update'))
);
@@ -491,7 +501,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('kits.edit', fn (Trail $trail, PredefinedKit $kit) =>
$trail->parent('kits.index', route('kits.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $kit->name]), route('kits.edit', $kit))
->push($kit->display_name, route('kits.show', $kit))
->push(trans('general.update'))
);
@@ -515,7 +526,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('statuslabels.edit', fn (Trail $trail, Statuslabel $statuslabel) =>
$trail->parent('statuslabels.index', route('statuslabels.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $statuslabel->name]), route('statuslabels.edit', $statuslabel))
->push($statuslabel->display_name, route('statuslabels.show', $statuslabel))
->push(trans('general.update'))
);
@@ -549,7 +561,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('suppliers.edit', fn (Trail $trail, Supplier $supplier) =>
$trail->parent('suppliers.index', route('suppliers.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $supplier->name]), route('suppliers.edit', $supplier))
->push($supplier->display_name, route('suppliers.show', $supplier))
->push(trans('general.update'))
);
@@ -607,7 +620,8 @@ class BreadcrumbsServiceProvider extends ServiceProvider
Breadcrumbs::for('users.edit', fn (Trail $trail, User $user) =>
$trail->parent('users.index', route('users.index'))
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $user->name]), route('users.edit', $user))
->push($user->display_name, route('users.show', $user))
->push(trans('general.update'))
);
-31
View File
@@ -1,31 +0,0 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class MacroServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
// require base_path() . '/resources/macros/community_types.php';
foreach (glob(base_path('resources/macros/*.php')) as $filename) {
require_once $filename;
}
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
-5
View File
@@ -14,10 +14,6 @@
{
"type": "vcs",
"url": "https://github.com/grokability/laravel-scim-server"
},
{
"type": "vcs",
"url": "https://github.com/grokability/html"
}
],
"require": {
@@ -51,7 +47,6 @@
"laravel/socialite": "^5.6",
"laravel/tinker": "^2.6",
"laravel/ui": "^4.0",
"laravelcollective/html": "6.x-dev",
"league/csv": "^9.7",
"league/flysystem-aws-s3-v3": "^3.0",
"livewire/livewire": "^4.0",
Generated
+2 -76
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "58603818d33285d78c0c8655385e7c0e",
"content-hash": "3eb217f961e55b3e6d0a1fdd6b812fda",
"packages": [
{
"name": "alek13/slack",
@@ -3310,79 +3310,6 @@
},
"time": "2025-01-28T15:15:29+00:00"
},
{
"name": "laravelcollective/html",
"version": "6.x-dev",
"source": {
"type": "git",
"url": "https://github.com/grokability/html.git",
"reference": "944b7029c207914ecec437c0141b7a0e32d9e1a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/grokability/html/zipball/944b7029c207914ecec437c0141b7a0e32d9e1a1",
"reference": "944b7029c207914ecec437c0141b7a0e32d9e1a1",
"shasum": ""
},
"require": {
"illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"illuminate/routing": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"illuminate/session": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"illuminate/view": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"php": ">=7.2.5"
},
"require-dev": {
"illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"mockery/mockery": "~1.0",
"phpunit/phpunit": "~8.5|^9.5.10"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.x-dev"
},
"laravel": {
"providers": [
"Collective\\Html\\HtmlServiceProvider"
],
"aliases": {
"Form": "Collective\\Html\\FormFacade",
"Html": "Collective\\Html\\HtmlFacade"
}
}
},
"autoload": {
"psr-4": {
"Collective\\Html\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"license": [
"MIT"
],
"authors": [
{
"name": "Adam Engebretson",
"email": "adam@laravelcollective.com"
},
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "HTML and Form Builders for the Laravel Framework",
"homepage": "https://laravelcollective.com",
"support": {
"issues": "https://github.com/LaravelCollective/html/issues",
"source": "https://github.com/LaravelCollective/html"
},
"abandoned": "spatie/laravel-html",
"time": "2025-01-20T14:37:14+00:00"
},
{
"name": "lcobucci/jwt",
"version": "5.5.0",
@@ -16630,8 +16557,7 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"arietimmerman/laravel-scim-server": 20,
"laravelcollective/html": 20
"arietimmerman/laravel-scim-server": 20
},
"prefer-stable": false,
"prefer-lowest": false,
-4
View File
@@ -306,7 +306,6 @@ return [
*/
Intervention\Image\ImageServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
Spatie\Backup\BackupServiceProvider::class,
PragmaRX\Google2FALaravel\ServiceProvider::class,
Laravel\Passport\PassportServiceProvider::class,
@@ -332,7 +331,6 @@ return [
*/
App\Providers\BladeServiceProvider::class,
App\Providers\LivewireServiceProvider::class,
App\Providers\MacroServiceProvider::class,
App\Providers\SamlServiceProvider::class,
App\Providers\BreadcrumbsServiceProvider::class,
@@ -385,8 +383,6 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Form' => Collective\Html\FormFacade::class,
'Html' => Collective\Html\HtmlFacade::class,
'Google2FA' => PragmaRX\Google2FALaravel\Facade::class,
'Image' => Intervention\Image\ImageServiceProvider::class,
'Carbon' => Carbon\Carbon::class,
+1
View File
@@ -1,2 +1,3 @@
*.sqlite
*.journal
*.sqlite-journal
+1 -1
View File
@@ -28,7 +28,7 @@ class MaintenanceFactory extends Factory
'asset_id' => Asset::factory()->laptopZenbook(),
'supplier_id' => Supplier::factory(),
'asset_maintenance_type' => $this->faker->randomElement(['maintenance', 'repair', 'upgrade']),
'name' => $this->faker->name(),
'name' => $this->faker->sentence(3),
'start_date' => $this->faker->date(),
'is_warranty' => $this->faker->boolean(),
'notes' => $this->faker->paragraph(),
+4
View File
@@ -32,6 +32,10 @@ class SettingFactory extends Factory
'locale' => 'en-US',
'pwd_secure_min' => 10, // Match web setup
'email_domain' => 'example.org',
'header_color' => '#3c8dbc',
'link_dark_color' => '#5fa4cc',
'link_light_color' => '#296282;',
'nav_link_color' => '#FFFFFF',
];
}
}
-1
View File
@@ -687,7 +687,6 @@ return [
],
'breadcrumb_button_actions' => [
'edit_item' => 'Edit :name',
'checkout_item' => 'Checkout :name',
'checkin_item' => 'Checkin :name',
],
-113
View File
@@ -1,113 +0,0 @@
<?php
/**
* Macro helpers
*/
/**
* Country macro
* Generates the dropdown menu of countries for the profile form
*/
Form::macro('countries', function ($name = 'country', $selected = null, $class = null, $id = null) {
$idclause = (!is_null($id)) ? $id : '';
// Pull the autoglossonym array from the localizations translation file
$countries_array = trans('localizations.countries');
$select = '<select name="'.$name.'" class="'.$class.'" style="width:100%" '.$idclause.' aria-label="'.$name.'" data-placeholder="'.trans('localizations.select_country').'" data-allow-clear="true" data-tags="true">';
$select .= '<option value="" role="option">'.trans('localizations.select_country').'</option>';
foreach ($countries_array as $abbr => $country) {
// We have to handle it this way to handle deprecation warnings since you can't strtoupper on null
if ($abbr!='') {
$abbr = strtoupper($abbr);
}
// Loop through the countries configured in the localization file
$select .= '<option value="' . $abbr . '" role="option" ' . (($selected == $abbr) ? ' selected="selected" aria-selected="true"' : ' aria-selected="false"') . '>' . $country . '</option> ';
}
// If the country value doesn't exist in the array, add it as a new option and select it so we don't drop that data
if (!array_key_exists($selected, $countries_array)) {
$select .= '<option value="' . e($selected) . '" selected="selected" role="option" aria-selected="true">' . e($selected) .' *</option> ';
}
$select .= '</select>';
return $select;
});
/**
* Barcode macro
* Generates the dropdown menu of available 1D barcodes
*/
Form::macro('alt_barcode_types', function ($name = 'alt_barcode', $selected = null, $class = null) {
$barcode_types = [
'C128',
'C39',
'PDF417',
'EAN5',
'EAN13',
'UPCA',
'UPCE',
];
$select = '<select name="'.$name.'" class="'.$class.'" aria-label="'.$name.'">';
foreach ($barcode_types as $barcode_type) {
$select .= '<option value="'.$barcode_type.'"'.($selected == $barcode_type ? ' selected="selected" role="option" aria-selected="true"' : ' aria-selected="false"').'>'.$barcode_type.'</option> ';
}
$select .= '</select>';
return $select;
});
/**
* Barcode macro
* Generates the dropdown menu of available 2D barcodes
*/
Form::macro('barcode_types', function ($name = 'barcode_type', $selected = null, $class = null) {
$barcode_types = [
'QRCODE',
'DATAMATRIX',
];
$select = '<select name="'.$name.'" class="'.$class.'" aria-label="'.$name.'">';
foreach ($barcode_types as $barcode_type) {
$select .= '<option value="'.$barcode_type.'"'.($selected == $barcode_type ? ' selected="selected" role="option" aria-selected="true"' : ' aria-selected="false"').'>'.$barcode_type.'</option> ';
}
$select .= '</select>';
return $select;
});
Form::macro('username_format', function ($name = 'username_format', $selected = null, $class = null) {
$formats = [
'firstname.lastname' => trans('admin/settings/general.username_formats.firstname_lastname_format'),
'firstname' => trans('admin/settings/general.username_formats.first_name_format'),
'lastname' => trans('admin/settings/general.username_formats.last_name_format'),
'filastname' => trans('admin/settings/general.username_formats.filastname_format'),
'lastnamefirstinitial' => trans('admin/settings/general.username_formats.lastnamefirstinitial_format'),
'firstname_lastname' => trans('admin/settings/general.username_formats.firstname_lastname_underscore_format'),
'firstinitial.lastname' => trans('admin/settings/general.username_formats.firstinitial_lastname'),
'lastname_firstinitial' => trans('admin/settings/general.username_formats.lastname_firstinitial'),
'lastname.firstinitial' => trans('admin/settings/general.username_formats.lastname_dot_firstinitial_format'),
'firstnamelastname' => trans('admin/settings/general.username_formats.firstnamelastname'),
'firstnamelastinitial' => trans('admin/settings/general.username_formats.firstnamelastinitial'),
'lastname.firstname' => trans('admin/settings/general.username_formats.lastnamefirstname'),
];
$select = '<select name="'.$name.'" class="'.$class.'" style="width: 100%" aria-label="'.$name.'">';
foreach ($formats as $format => $label) {
$select .= '<option value="'.$format.'"'.($selected == $format ? ' selected="selected" role="option" aria-selected="true"' : ' aria-selected="false"').'>'.$label.'</option> '."\n";
}
$select .= '</select>';
return $select;
});
@@ -288,9 +288,9 @@
@if ((isset($infoPanelObj->parent)) && $infoPanelObj->parent))
@if ((isset($infoPanelObj->parent)) && ($infoPanelObj->parent))
<x-info-element icon_type="parent" title="{{ trans('admin/locations/table.parent') }}">
{{ $infoPanelObj->parent->display_name }}
<a href="{{ route('locations.show', $infoPanelObj->parent->id) }}">{{ $infoPanelObj->parent->display_name }}</a>
</x-info-element>
@endif
@@ -6,7 +6,7 @@
])
@if (!$slot->isEmpty())
<li {{ $attributes->merge(['class' => 'list-group-item']) }}>
<li {{ $attributes->merge(['class' => 'list-group-item']) }} id="{{ strtolower(str_slug($title)) }}">
@if ($icon_type)
<x-icon type="{{ $icon_type }}" :title="$title" class="fa-fw" style="{{ 'color: '.$icon_color.' !important' ?? '' }}" />
@@ -0,0 +1,35 @@
@props([
'name' => 'country',
'selected' => null,
])
@php
$countries_array = trans('localizations.countries');
@endphp
<select
name="{{ $name }}"
{{ $attributes->merge(['class' => 'select2']) }}
aria-label="{{ $name }}"
data-placeholder="{{ trans('localizations.select_country') }}"
data-allow-clear="true"
>
@foreach($countries_array as $abbreviation => $country)
@php
// We have to handle it this way to handle deprecation warnings since you can't strtoupper on null
if ($abbreviation!='') {
$abbreviation = strtoupper($abbreviation);
}
@endphp
<option value="{{ $abbreviation }}" {{ $selected === $abbreviation ? 'selected' : '' }}>
{{ $country }}
</option>
@endforeach
{{-- If the country value doesn't exist in the array, add it as a new option and select it so we don't drop that data --}}
@if (!array_key_exists($selected, $countries_array)) {
<option value="{{ e($selected) }}" selected="selected" role="option" aria-selected="true"> {{ e($selected) }} *</option> ';
@endif
</select>
@@ -0,0 +1,27 @@
@php
$formats = [
'firstname.lastname' => trans('admin/settings/general.username_formats.firstname_lastname_format'),
'firstname' => trans('admin/settings/general.username_formats.first_name_format'),
'lastname' => trans('admin/settings/general.username_formats.last_name_format'),
'filastname' => trans('admin/settings/general.username_formats.filastname_format'),
'lastnamefirstinitial' => trans('admin/settings/general.username_formats.lastnamefirstinitial_format'),
'firstname_lastname' => trans('admin/settings/general.username_formats.firstname_lastname_underscore_format'),
'firstinitial.lastname' => trans('admin/settings/general.username_formats.firstinitial_lastname'),
'lastname_firstinitial' => trans('admin/settings/general.username_formats.lastname_firstinitial'),
'lastname.firstinitial' => trans('admin/settings/general.username_formats.lastname_dot_firstinitial_format'),
'firstnamelastname' => trans('admin/settings/general.username_formats.firstnamelastname'),
'firstnamelastinitial' => trans('admin/settings/general.username_formats.firstnamelastinitial'),
'lastname.firstname' => trans('admin/settings/general.username_formats.lastnamefirstname'),
];
@endphp
<x-input.select {{ $attributes }}>
@foreach($formats as $format => $label)
<option
value="{{ $format }}"
@selected($selected == $format)
>
{{ $label }}
</option>
@endforeach
</x-input.select>
@@ -20,7 +20,7 @@
@if (($options) && (count($options) > 0))
<select class="redirect-options form-control select2" data-minimum-results-for-search="Infinity" name="redirect_option" style="min-width: 250px"{{ ($disabled_select ? ' disabled' : '') }}>
@foreach ($options as $key => $value)
<option value="{{ $key }}"{{ Session::get('redirect_option') == $key ? ' selected' : ''}}>
<option value="{{ $key }}"{{ session('redirect_option') == $key ? ' selected' : ''}}>
{{ $value }}
</option>
@endforeach
@@ -5,6 +5,7 @@
'api_url' => null,
'show_column_search' => false,
'show_advanced_search' => false,
'show_search' => true,
'fixed_number' => false,
'fixed_right_number' => false,
'sort_order' => 'asc',
@@ -26,6 +27,7 @@
id="{{ $name }}ListingTable"
data-show-columns-search="{{ $show_column_search }}"
data-show-advanced-search="{{ $show_advanced_search }}"
data-search="{{ $show_search }}"
data-footer-style="footerStyle"
data-show-footer="true"
@@ -51,7 +51,7 @@
@foreach($custom_fieldsets AS $fieldset)
<tr>
<td>
{{ link_to_route("fieldsets.show",$fieldset->name,['fieldset' => $fieldset->id]) }}
<a href="{{ route('fieldsets.show', ['fieldset' => $fieldset->id]) }}">{{ $fieldset->name }}</a>
</td>
<td>
{{ $fieldset->fields->count() }}
+1 -1
View File
@@ -287,7 +287,7 @@
$("#selected_status_status").removeClass('text-danger');
$("#selected_status_status").addClass('text-success');
$("#selected_status_status").html('<x-icon type="checkmark" /> {{ trans('admin/hardware/form.asset_deployable')}}');
$("#selected_status_status").html('<x-icon type="checkmark" /> {{ trans_choice('admin/hardware/form.asset_deployable', 1)}}');
} else {
+2 -2
View File
@@ -158,7 +158,7 @@
if (data.status == 'success') {
$('#audited tbody').prepend("<tr class='success'><td>" + data.payload.asset_tag + "</td><td>" + data.messages + "</td><td>" + data.payload.status_label + " (" + data.payload.status_type + ")</td><td>" + data.payload.note + "</td><td><i class='fas fa-check text-success' style='font-size:18px;'></i></td></tr>");
@if ($user->enable_sounds)
@if ($user?->enable_sounds)
var audio = new Audio('{{ config('app.url') }}/sounds/success.mp3');
audio.play()
@endif
@@ -182,7 +182,7 @@
});
function handleAuditFail (data, asset_tag) {
@if ($user->enable_sounds)
@if ($user?->enable_sounds)
var audio = new Audio('{{ config('app.url') }}/sounds/error.mp3');
audio.play()
@endif
+1 -1
View File
@@ -553,7 +553,7 @@
{!! $asset->checkInvalidNextAuditDate() ? '<i class="fas fa-exclamation-triangle text-orange" aria-hidden="true"></i>' : '' !!}
{{ Helper::getFormattedDateObject($audit_log->created_at, 'datetime', false) }}
@if ($audit_log->user)
({{ link_to_route('users.show', $audit_log->user->display_name, [$audit_log->user->id]) }})
(<a href="{{ route('users.show', $audit_log->user->id) }}">{{ $audit_log->user->display_name }}</a>)
@endif
</div>
+28 -14
View File
@@ -154,6 +154,9 @@
color: var(--link-hover) !important;
}
label.form-control {
color: var(--color-fg) !important;
}
.footer-links a {
color: var(--link-color) !important;
@@ -942,9 +945,11 @@
input[type="email"]:required,
input[type="password"]:required,
input[type="tel"]:required,
select:required,
input:required,
textarea:required
{
border-right: 5px solid var(--text-warning) !important;
border-right: 5px solid orange !important;
}
.bootstrap-table .fixed-table-container .table tbody tr.selected td {
@@ -1128,6 +1133,15 @@
</li>
@endcan
@can('index', \App\Models\User::class)
<li aria-hidden="true"{!! (request()->is('users*') ? ' class="active"' : '') !!}>
<a href="{{ route('users.index') }}" {{$snipeSettings->shortcuts_enabled == 1 ? "accesskey=6" : ''}} tabindex="-1" data-tooltip="true" data-placement="bottom" data-title="{{ trans('general.users') }}">
<x-icon type="users" class="fa-fw" />
<span class="sr-only">{{ trans('general.users') }}</span>
</a>
</li>
@endcan
@can('index', \App\Models\Asset::class)
<li>
<form class="navbar-form navbar-left form-inline" role="search" action="{{ route('findbytag/hardware') }}" method="get">
@@ -1234,7 +1248,7 @@
<ul class="dropdown-menu">
<!-- User image -->
@can('self.profile')
<li {!! (request()->is('account/profile') ? ' class="active"' : '') !!}>
<li {!! (request()->is('account/view-assets') ? ' class="active"' : '') !!}>
<a href="{{ route('view-assets') }}">
<x-icon type="checkmark" class="fa-fw" />
{{ trans('general.viewassets') }}
@@ -1258,7 +1272,7 @@
</li>
@endcan
<li>
<li {!! (request()->is('account/password') ? ' class="active"' : '') !!}>
<a href="{{ route('profile') }}">
<x-icon type="user" class="fa-fw" />
{{ trans('general.editprofile') }}
@@ -1267,7 +1281,7 @@
@can('self.profile')
@if (Auth::user()->ldap_import!='1')
<li>
<li {!! (request()->is('account/profile') ? ' class="active"' : '') !!}>
<a href="{{ route('account.password.index') }}">
<x-icon type="password" class="fa-fw" />
{{ trans('general.changepassword') }}
@@ -1283,7 +1297,7 @@
</li>
@can('self.api')
<li>
<li {!! (request()->is('account/api') ? ' class="active"' : '') !!}>
<a href="{{ route('user.api') }}">
<x-icon type="api-key" class="fa-fw" />
{{ trans('general.manage_api_keys') }}
@@ -1331,7 +1345,7 @@
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu" data-widget="tree" {{ \App\Helpers\Helper::determineLanguageDirection() == 'rtl' ? 'style="margin-right:12px' : '' }}>
@can('admin')
<li {!! (\Request::route()->getName()=='home' ? ' class="active"' : '') !!} class="firstnav">
<li {!! (\request()->route()->getName()=='home' ? ' class="active"' : '') !!} class="firstnav">
<a href="{{ route('home') }}">
<x-icon type="dashboard" class="fa-fw" />
<span>{{ trans('general.dashboard') }}</span>
@@ -1346,7 +1360,7 @@
<x-icon type="angle-left" class="pull-right fa-fw"/>
</a>
<ul class="treeview-menu">
<li>
<li {!! (!request()->query('status') && (request()->is('hardware')) ? ' class="active"' : '') !!}>
<a href="{{ url('hardware') }}">
<x-icon type="circle" class="text-grey fa-fw"/>
{{ trans('general.list_all') }}
@@ -1369,48 +1383,48 @@
@endif
<li id="deployed-sidenav-option" {!! (Request::query('status') == 'Deployed' ? ' class="active"' : '') !!}>
<li id="deployed-sidenav-option" {!! (request()->query('status') == 'Deployed' ? ' class="active"' : '') !!}>
<a href="{{ url('hardware?status=Deployed') }}">
<x-icon type="circle" class="text-blue fa-fw" />
{{ trans('general.deployed') }}
<span class="badge">{{ (isset($total_deployed_sidebar)) ? $total_deployed_sidebar : '' }}</span>
</a>
</li>
<li id="rtd-sidenav-option"{!! (Request::query('status') == 'RTD' ? ' class="active"' : '') !!}>
<li id="rtd-sidenav-option"{!! (request()->query('status') == 'RTD' ? ' class="active"' : '') !!}>
<a href="{{ url('hardware?status=RTD') }}">
<x-icon type="circle" class="text-green fa-fw" />
{{ trans('general.ready_to_deploy') }}
<span class="badge">{{ (isset($total_rtd_sidebar)) ? $total_rtd_sidebar : '' }}</span>
</a>
</li>
<li id="pending-sidenav-option"{!! (Request::query('status') == 'Pending' ? ' class="active"' : '') !!}><a href="{{ url('hardware?status=Pending') }}">
<li id="pending-sidenav-option"{!! (request()->query('status') == 'Pending' ? ' class="active"' : '') !!}><a href="{{ url('hardware?status=Pending') }}">
<x-icon type="circle" class="text-orange fa-fw" />
{{ trans('general.pending') }}
<span class="badge">{{ (isset($total_pending_sidebar)) ? $total_pending_sidebar : '' }}</span>
</a>
</li>
<li id="undeployable-sidenav-option"{!! (Request::query('status') == 'Undeployable' ? ' class="active"' : '') !!} ><a
<li id="undeployable-sidenav-option"{!! (request()->query('status') == 'Undeployable' ? ' class="active"' : '') !!} ><a
href="{{ url('hardware?status=Undeployable') }}">
<x-icon type="x" class="text-red fa-fw" />
{{ trans('general.undeployable') }}
<span class="badge">{{ (isset($total_undeployable_sidebar)) ? $total_undeployable_sidebar : '' }}</span>
</a>
</li>
<li id="byod-sidenav-option"{!! (Request::query('status') == 'byod' ? ' class="active"' : '') !!}><a
<li id="byod-sidenav-option"{!! (request()->query('status') == 'byod' ? ' class="active"' : '') !!}><a
href="{{ url('hardware?status=byod') }}">
<x-icon type="x" class="text-red fa-fw" />
{{ trans('general.byod') }}
<span class="badge">{{ (isset($total_byod_sidebar)) ? $total_byod_sidebar : '' }}</span>
</a>
</li>
<li id="archived-sidenav-option"{!! (Request::query('status') == 'Archived' ? ' class="active"' : '') !!}><a
<li id="archived-sidenav-option"{!! (request()->query('status') == 'Archived' ? ' class="active"' : '') !!}><a
href="{{ url('hardware?status=Archived') }}">
<x-icon type="x" class="text-red fa-fw" />
{{ trans('admin/hardware/general.archived') }}
<span class="badge">{{ (isset($total_archived_sidebar)) ? $total_archived_sidebar : '' }}</span>
</a>
</li>
<li id="requestable-sidenav-option"{!! (Request::query('status') == 'Requestable' ? ' class="active"' : '') !!}><a
<li id="requestable-sidenav-option"{!! (request()->query('status') == 'Requestable' ? ' class="active"' : '') !!}><a
href="{{ url('hardware?status=Requestable') }}">
<x-icon type="checkmark" class="text-blue fa-fw" />
{{ trans('admin/hardware/general.requestable') }}
+2 -1
View File
@@ -79,6 +79,7 @@
<x-slot:content>
<x-table
show_search="false"
api_url="{{ route('api.licenses.seats.index', [$license->id, 'status' => 'available']) }}"
:presenter="\App\Presenters\LicensePresenter::dataTableLayoutSeats()"
export_filename="export-{{ str_slug($license->name) }}-available-{{ date('Y-m-d') }}"
@@ -128,7 +129,7 @@
<x-slot:buttons>
<x-button.checkout permission="checkout" :item="$license" :route="route('licenses.freecheckout', $license->id)" />
<x-button.checkout permission="checkout" :item="$license" :route="route('licenses.checkout', $license->id)" />
<x-button.edit :item="$license" :route="route('licenses.edit', $license->id)" />
<x-button.clone :item="$license" :route="route('clone/license', $license->id)" />
<x-button.delete :item="$license" />
+7 -1
View File
@@ -32,7 +32,13 @@
<div class="dynamic-form-row">
<div class="col-md-3 col-xs-12 country"><label for="modal-country">{{ trans('general.country') }}:</label></div>
<div class="col-md-9 col-xs-12">{!! Form::countries('country', old('country'), 'select2 country',"modal-country") !!}</div>
<div class="col-md-9 col-xs-12">
<x-input.country-select
name="country"
:selected="old('country')"
id="modal-country"
/>
</div>
</div>
</form>
</div>
+1 -1
View File
@@ -46,7 +46,7 @@
</div> <!-- /.modal-body-->
<div class="modal-footer">
<a href="#" class="pull-left" data-dismiss="modal">{{ trans('button.cancel') }}</a>
<button type="submit" class="btn btn-theme">{{ trans('button.upload') }}</button>
<button type="submit" class="btn btn-theme" formnovalidate>{{ trans('button.upload') }}</button>
</div>
</form>
</div>
@@ -34,7 +34,10 @@
<div class="form-group {{ $errors->has('country') ? ' has-error' : '' }}">
<label for="country" class="col-md-3 control-label">{{ trans('general.country') }}</label>
<div class="col-md-7">
{!! Form::countries('country', old('country', $item->country), 'select2') !!}
<x-input.country-select
name="country"
:selected="old('country', $item->country)"
/>
<p class="help-block">{{ trans('general.countries_manually_entered_help') }}</p>
{!! $errors->first('country', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
+6 -1
View File
@@ -102,7 +102,12 @@
<label for="username_format" class="col-md-3 control-label">{{ trans('admin/settings/general.username_formats.username_format') }}</label>
<div class="col-md-8">
{!! Form::username_format('username_format', old('username_format', $setting->username_format), 'select2') !!}
<x-input.username-select
name="username_format"
:selected="old('username_format', $setting->username_format)"
style="width: 100%"
aria-label="username_format"
/>
{!! $errors->first('username_format', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="help-block">
+1 -13
View File
@@ -80,19 +80,7 @@
<!-- start components tab pane -->
@can('view', \App\Models\Component::class)
<x-tabs.pane name="components" class="{{ $supplier->components->count() == 0 ? 'hidden-print' : '' }}">
<x-slot:header>
{{ trans('general.components') }}
</x-slot:header>
<x-table
show_advanced_search="true"
buttons="componentButtons"
api_url="{{ route('api.components.index', ['supplier_id' => $supplier->id]) }}"
:presenter="\App\Presenters\ComponentPresenter::dataTableLayout()"
export_filename="export-{{ str_slug($supplier->name) }}-components-{{ date('Y-m-d') }}"
/>
<x-table.components name="components" :route="route('api.components.index', ['supplier_id' => $supplier->id])" />
</x-tabs.pane>
@endcan
<!-- end components tab pane -->
+6 -2
View File
@@ -330,7 +330,7 @@
<!-- Company -->
@if ((Gate::allows('canEditAuthFields', $user)) && (\App\Models\Company::canManageUsersCompanies()))
@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.select_company'), 'fieldname' => 'company_id'])
@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.company'), 'fieldname' => 'company_id'])
@else
@if ($user->company)
<div class="form-group">
@@ -502,7 +502,11 @@
<div class="form-group{{ $errors->has('country') ? ' has-error' : '' }}">
<label class="col-md-3 control-label" for="country">{{ trans('general.country') }}</label>
<div class="col-md-6">
{!! Form::countries('country', old('country', $user->country), 'col-md-12 select2') !!}
<x-input.country-select
name="country"
:selected="old('country', $user->country)"
class="col-md-12"
/>
<p class="help-block">{{ trans('general.countries_manually_entered_help') }}</p>
{!! $errors->first('country', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
+2 -2
View File
@@ -8,7 +8,7 @@ use Illuminate\Support\Facades\Route;
*/
Route::group(['prefix' => 'accessories', 'middleware' => ['auth']], function () {
Route::get(
'{accessoryID}/checkout',
'{accessory}/checkout',
[Accessories\AccessoryCheckoutController::class, 'create']
)->name('accessories.checkout.show');
@@ -31,7 +31,7 @@ Route::group(['prefix' => 'accessories', 'middleware' => ['auth']], function ()
[Accessories\AccessoriesController::class, 'getClone']
)->name('clone/accessories');
Route::post('{accessoryId}/clone',
Route::post('{accessory}/clone',
[Accessories\AccessoriesController::class, 'postCreate']
);
+1 -1
View File
@@ -18,7 +18,7 @@ Route::group(['prefix' => 'locations', 'middleware' => ['auth']], function () {
Route::post(
'{location}/restore',
[LocationsController::class, 'postRestore']
)->name('locations.restore');
)->name('locations.restore')->withTrashed();
Route::get('{locationId}/clone',
[LocationsController::class, 'getClone']
+2 -10
View File
@@ -52,20 +52,12 @@ Route::group(['prefix' => 'users', 'middleware' => ['auth']], function () {
)->name('users.clone.store')->withTrashed();
Route::post(
'{userId}/restore',
'{user}/restore',
[
Users\UsersController::class,
'getRestore'
]
)->name('users.restore.store');
Route::get(
'{userId}/unsuspend',
[
Users\UsersController::class,
'getUnsuspend'
]
)->name('unsuspend/user');
)->name('users.restore.store')->withTrashed();
Route::post(
'{userId}/password',