snipe-it icon indicating copy to clipboard operation
snipe-it copied to clipboard

Added #17494: Advanced-search and predefined filters

Open cz-lucas opened this issue 1 month ago • 5 comments

Added #17494: Advanced-search and predefined filters

New functionality

Advanced search:

  • Added new advanced-search which allows filtering on backend
  • Added functionality to manage private and public filters. The provided new permissions for new functionality
  • Create new settings-page to manage filters

API:

  • Added API to manage the predefined filters

Database:

  • Added tables for predefined filters and predefined filter permissions

Testing:

  • Added plenty of unit- and feature tests for the advanced search and predefined filters
  • Added tests for the "old" advanced search

Screenshots

Advanced search: image Predefined filter create modal: image Predefined filter settings page image

cz-lucas avatar Nov 28 '25 12:11 cz-lucas

:warning: We detected 1 security issue in this pull request:

Insecure Use of Dangerous Function (1)
Severity Details Docs
Medium Title: Dynamic evaluation of untrusted input (Frontend)
https://github.com/grokability/snipe-it/blob/a89f75b108dbba270d9b6c45ad8a65c8d5aa2037/public/js/dist/advanced-search.js#L1
:books:

More info on how to fix Insecure Use of Dangerous Function in JavaScript.


👉 Go to the dashboard for detailed results.

📥 Happy? Share your feedback with us.

guardrails[bot] avatar Nov 28 '25 12:11 guardrails[bot]

Hi there and thank you for you PR.

It looks like a lot of work went into this but that also means there are a lot of changed files which makes reviewing this difficult 😅.

In order for the team to start reviewing this can you please make the following changes:

  • [x] It looks like a formatter was run for a lot of lines that aren't relevant to the feature. Please remove the formatting changes that are not on lines added or changed while building the feature this PR focuses on.
    • This is helpful for the reviewers before the code is merged and also in the future when we want to track the changes to a file. Formatting for the sake of formatting makes tracking down relevant changes to a file more difficult in the future.
  • [x] Please remove files/changes that seem to be relevant to your local dev environment like the references to Codacy.
  • [ ] Please remove the build assets.
    • Those changes should not be included in PRs since they make reviewing a lot more difficult. If needed we build them locally when testing.
  • [x] Please remove the translations except for our source of truth, en-US.
  • [ ] Please remove the .gitignore files in the storage directories.
    • I don't think they are necessary?
  • [ ] It looks like this PR includes changes that aren't relevant to advanced search and pre-defined filters (like changes to alerts/notifications). Please move those changes to another PR so both features/changes can be reviewed individually.
  • [x] Please provide details about the technical implementation in the PR description.
    • The screenshots are really appreciated so we can get an overview of the new functionality but a walkthrough of the actual code added and changed will go a long way in making the PR review more manageable.

It may seem like a lot but these changes are needed before the team can dive in and start reviewing. We need to get the 21k changed lines down to something manageable for our devs.

Again, thank you for your contribution!

marcusmoore avatar Dec 03 '25 20:12 marcusmoore

Sorry, maybe I should have been more specific but the goal is not completely remove the build like done in a261b85 (#18264), but to remove the changes to those files in comparison to what is on develop. In other words, the PR diff should show no changes for the frontend assets that are built.


When I talked about removing irrelevant code-formatting changes I meant reverting these types of changes: image The relevant lines for this PR are 165/166 but there are 6 other lines touched that should not be included.


In general, having 285 files changed with thousands of lines touched is un-reviewable: image

marcusmoore avatar Dec 04 '25 18:12 marcusmoore

Here is an overview of all relevant files changed:

Backend

Controllers

  • app/Http/Controllers/Api/AssetsController.php: Added new filtering using the FilterService.
  • app/Http/Controllers/Api/GroupsController.php: Added selectlist for the group-select dropdown.
  • app/Http/Controllers/Api/PredefinedFilterController.php: Controller for managing predefined filters.
  • app/Http/Controllers/Api/PredefinedFilterPermissionController.php: Controller to manage permissions for predefined filters.
  • app/Http/Controllers/AssetsController.php: Added logic to apply predefined filters using the predefinedFilterID parameter in the URL.
  • app/Http/Controllers/PredefinedFilterController.php: Controller for the predefined filter page in settings.

Models

  • app/Models/Asset.php: Integrated FilterService for advanced filtering.
  • app/Models/PredefinedFilter.php: Model for predefined filters.
  • app/Models/PredefinedFilterPermission.php: Model for predefined filter permissions.

Policies & Providers

  • app/Policies/PredefinedFilterPolicy.php: Policy for predefined filters.
  • app/Providers/AuthServiceProvider.php: Registered permissions for predefined filters.

Services

  • app/Services/FilterService/FilterService.php: New service containing filtering logic.
  • app/Services/PredefinedFilterService.php: Service for CRUD operations on predefined filters.

Transformers

  • app/Http/Transformers/PredefinedFiltersTransformer.php: Transformer for predefined filters.

Migrations

  • database/migrations/2025_08_29_120952_create_predefined_filters_table.php: Create predefined filters table.
  • database/migrations/2025_09_05_054824_create_predefined_filters_permissions.php: Create predefined filter permissions table.
  • database/migrations/2025_09_25_120708_make_predefined_filter_permissions_unique.php: Enforce unique combination of predefinedFilterId and permissionGroupId (We could have moved this into the 2025_08_29_120952_create_predefined_filters_table migration, but we noticed during development that it was a good idea to make this unique, and we thought that creating another migration would be the cleaner solution.).

Frontend

CSS

  • resources/assets/css/components/advancedSearch/advanced-search-index.css: Styles for the advanced search index page.
  • resources/assets/css/components/advancedSearch/advanced-search.css: Styles for the advanced search drawer.
  • resources/assets/css/components/advancedSearch/floating-buttons.css: Styles for floating buttons in the filter drawer.

JavaScript

  • resources/assets/js/advancedSearch/advanced-search-index.js: Logic for opening/closing the advanced search drawer.
  • resources/assets/js/advancedSearch/advanced-search.js: Main JS file for advanced search.
  • resources/assets/js/advancedSearch/apiService.js: Backend communication for fetching predefined filters.
  • resources/assets/js/advancedSearch/filterFormManager.js: Manages filter inputs.
  • resources/assets/js/advancedSearch/filterInputs.js: Implements filter input classes.
  • resources/assets/js/advancedSearch/filterUiController.js: Handles loading/updating/saving predefined filters.
  • resources/assets/js/advancedSearch/floating-buttons.js: Logic for floating buttons in the filter drawer.
  • resources/assets/js/advancedSearch/search-inputs.js: Expands select2 fields on focus.
  • resources/assets/js/simpleDIContainer.js: A simple implementation of a DI-Container that we implemented ourselves because we didn't want to add external dependencies.

Views

  • resources/views/hardware/index.blade.php: Restructured to embed advanced search.
  • resources/views/livewire/partials/advancedsearch/modal.blade.php: Modal for managing predefined filters.
  • resources/views/predefined-filters/index.blade.php: Page to manage predefined filters.

Partials

  • resources/views/partials/advanced-search/advanced-search-translations.blade.php: Sets translations for advanced search.
  • resources/views/partials/advanced-search/advanced-search.blade.php: Main advanced search component.
  • resources/views/partials/advanced-search/search-inputs.blade.php: Search input components.
  • resources/views/partials/forms/edit/*: Moved dropdowns to components for advanced search.
  • resources/views/partials/select/dropdowns/*: Dropdown components for forms/edit.

Tests

Feature Tests

  • tests/Feature/AssetQuery/*: Tests for different asset filters.
  • tests/Feature/AssetQuery/Api/*: API tests for asset filters.
  • tests/Feature/PredefinedFilter/Api/PredefinedFilterControllerTest.php: Tests for PredefinedFilterController.
  • tests/Feature/PredefinedFilter/UI/PredefinedFilterModalTest.php: Tests for the predefined filter modal UI.

Unit Tests

  • tests/Unit/Models/AssetUnitTest.php: Unit tests for the Asset model.

Database

We've added two tables to store the predefined filters:

  • predefined_filters to store the predefined filters. The actual filter-data is stored as a json-string
  • predefined_filter_permissions to store which user has which permissions to create/edit/view/delete a predefined filter

cz-lucas avatar Dec 08 '25 09:12 cz-lucas

Hi there,

we have made the necessary changes you mentioned earlier.

Summary:

  • reverted the formatting stuff
  • removed files related to our development environment
  • removed all build assets we did not use
  • removed Translations except en-US
  • removed .gitignore
  • moved notifications to a separate PR (#18290)
  • Provided technical details (https://github.com/grokability/snipe-it/pull/18264#issuecomment-3625866640)

JonasGoseberg avatar Dec 09 '25 12:12 JonasGoseberg

Predefined Filter Feature

In addition to the previous explanation, this section covers the new predefined filter functionality.

Summary This part adds a feature to save the current filter configuration, allowing users to quickly reapply it later.

Database Structure

We added two new tables:

  1. predefined_filters

This table stores each predefined filter and its associated metadata.

Field Type Null Key Default Extra Explanation
id bigint(20) unsigned NO PRI NULL auto_increment Primary key
name varchar(191) NO   NULL   Name of the filter
created_by int(10) unsigned NO   NULL   Creator user ID
created_at timestamp YES   current_timestamp()   Creation time
updated_at timestamp YES   current_timestamp() on update current_timestamp() Last update time
deleted_at timestamp YES   NULL   Soft delete time
filter_data longtext NO   NULL   Actual filter data (JSON)
is_public tinyint(1) NO   0   Whether the filter is public
object_type varchar(191) YES   asset   Defaults to asset (placeholder for future use)
Filter Examples

Standard fields (e.g. company, asset_tag)

[
  {
    "field": "company",
    "value": [8, "com"],
    "operator": "contains",
    "logic": "AND"
  }
]

Explanation:

  • 8 → exact company ID
  • "com" → substring used in the contains search

Custom fields

[
  {
    "field": "_snipeit_ram_3",
    "value": "32",
    "operator": "equals",
    "logic": "AND"
  }
]

Explanation:

  • Custom fields use the same structure as standard fields
  • Prefix snipeit_ follows the pattern in the assets table

Checked-out-to (assigned_to)

[
  {
    "field": "assigned_to",
    "value": {
      "type": "App\\Models\\Asset",
      "value": "Demo"
    },
    "operator": "equals",
    "logic": "AND"
  }
]

Explanation:

  • Handles relationships to other objects (e.g., assets or users)
  • "type" specifies the related model
  • "value" specifies the related entity

Date range filters

[
  {
    "field": "purchase_date",
    "value": {
      "startDate": "2024-03-14",
      "endDate": "2025-12-14"
    },
    "operator": "equals",
    "logic": "AND"
  }
]

Explanation:

  • Supports filtering by date ranges
  • "startDate" and "endDate" define the range
  1. predefined_filter_permissions

The predefined_filter_permissions table is a many-to-many mapping between predefined filters and permission groups. It defines which groups have access to which filters.

Field Type Null Key Default Extra Explanation
id bigint(20) unsigned NO PRI NULL auto_increment Primary key
predefined_filter_id bigint(20) unsigned NO MUL NULL   Linked predefined filter ID
permission_group_id bigint(20) unsigned NO   NULL   Linked permission group ID
created_by int(10) unsigned NO   NULL   Creator user ID
created_at timestamp YES   NULL   Creation time
updated_at timestamp YES   NULL   Last update time

Permission System

We added four new permissions for predefined filters:

  • create
  • view
  • edit
  • delete

How it works:

  • A user can perform an action on a predefined filter if they belong to a permission group linked to that filter and the group has the corresponding permission.
  • Superusers bypass all restrictions and can perform any action.

JonasGoseberg avatar Dec 10 '25 09:12 JonasGoseberg

Thank you for addressing the changes requested (I know it was a lot). This is a big PR (understandably) so our team is going to need some time to review and consider it.

marcusmoore avatar Dec 10 '25 20:12 marcusmoore