Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fcb5162
Added first version of the new modal
cz-lucas Sep 29, 2025
c9c3d45
Added modalactiontype
cz-lucas Sep 30, 2025
db79291
Now a predefined filter is loaded and the name, visibilty and groups …
cz-lucas Sep 30, 2025
04267d1
Now the select2 dropdown in the modal works
cz-lucas Sep 30, 2025
86b94b9
Fixed error in dropdown
cz-lucas Sep 30, 2025
4439dd8
Continued with the modal
cz-lucas Sep 30, 2025
5f02114
Some updates for the dropdown in the modal
cz-lucas Oct 1, 2025
af71a91
Now an array with all selected groups is send to the backend 🥳
cz-lucas Oct 1, 2025
2ea463f
Added methods for create, update and delete
cz-lucas Oct 2, 2025
9d18d3f
Deletion is now possible
cz-lucas Oct 2, 2025
d8ccc46
Creation works also now
cz-lucas Oct 2, 2025
08acddb
Now the update works (execpt for groups)
cz-lucas Oct 2, 2025
2276834
Fixed updates for groups
cz-lucas Oct 2, 2025
226d451
Added some testcases and removed old modal
cz-lucas Oct 2, 2025
dc36f24
Added some testcases and removed old modal
cz-lucas Oct 2, 2025
d9ded83
Disabling group select when the visibility is set to private
cz-lucas Oct 6, 2025
18a6794
Made it controllable using the keyboard
cz-lucas Oct 6, 2025
82c99cc
Merge branch 'develop' into refactor-modal
cz-lucas Oct 6, 2025
9055043
Implemented comments in pullrequest imbus/snipe-it/pull#16
cz-lucas Oct 6, 2025
694ad5c
Merge branch 'refactor-modal' of github.com:imbus/snipe-it into refac…
cz-lucas Oct 6, 2025
f6928a5
Merge branch 'develop' into refactor-modal
cz-lucas Oct 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 245 additions & 0 deletions app/Livewire/Partials/AdvancedSearch/Modal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
<?php

namespace App\Livewire\Partials\Advancedsearch;

use Livewire\Component;
use Livewire\Attributes\On;
use Livewire\Attributes\Validate;

use App\Models\PredefinedFilter;
use App\Services\PredefinedFilterService;

enum FilterVisibility: string
{
case Private = "private";
case Public = "public";
}

enum AdvancedsearchModalAction: string
{
case Create = "create";
case Edit = "edit";
case Delete = "delete";
}

class Modal extends Component
{
public $showModal = false;
public AdvancedsearchModalAction $modalActionType;

#[Validate("required")]
public ?string $name = "";
public FilterVisibility $visibility = FilterVisibility::Private;
public $groupSelect = [];
public array $groupSelectOtherOptions = [];

protected $listeners = ["groupSelect"];

public ?int $filterId;
public $filterData;

#[On("openPredefinedFiltersModal")]
public function openPredefinedFiltersModal(
PredefinedFilterService $predefinedFilterService,
string $action,
?array $predefinedFilterData = null,
?int $predefinedFilterId = null
) {
$this->modalActionType = AdvancedsearchModalAction::from($action);
$this->showModal = true;
$this->groupSelect = [];
$this->groupSelectOtherOptions = [];
$this->filterData = $predefinedFilterData;
$this->filterId = $predefinedFilterId;

$user = auth()->user();
$this->groupSelectOtherOptions = $user
->groups()
->pluck("id")
->toArray();

if (
$this->modalActionType === AdvancedsearchModalAction::Edit &&
$predefinedFilterId !== null
) {
$predefinedFilter = $predefinedFilterService->getFilterById(
$predefinedFilterId
);
$this->name = $predefinedFilter["name"];

if ($predefinedFilter["is_public"] === 1) {
$this->visibility = FilterVisibility::Public;
} else {
$this->visibility = FilterVisibility::Private;
}

foreach ($predefinedFilter["permissions"] as $permission) {
array_push(
$this->groupSelect,
$permission->permission_group_id
);
}

$this->groupSelectOtherOptions = array_diff(
$this->groupSelectOtherOptions,
$this->groupSelect
);
}

$this->dispatch("openPredefinedFiltersModalEvent");
}

#[On("closePredefinedFiltersModal")]
public function closePredefinedFiltersModal()
{
$this->showModal = false;
$this->groupSelect = [];
$this->groupSelectOtherOptions = [];
$this->filterData = null;
$this->filterId = null;
$this->name = "";
$this->dispatch("closePredefinedFiltersModalEvent");
}

#[On("savePredefinedFiltersModal")]
public function savePredefinedFiltersModal(
PredefinedFilterService $predefinedFilterService
) {
$this->validate();

$validated = [
"name" => $this->name,
"filter_data" => $this->filterData,
"is_public" =>
$this->visibility === FilterVisibility::Public ? 1 : 0,
"permissions" => self::formatPermissions($this->groupSelect),
];

$createFilterResponse = $predefinedFilterService->createFilter($validated);

if ($createFilterResponse === true) {
$this->dispatch('showNotification', [
'type' => 'success',
'title' => trans('general.notification_success'),
'message' => trans('general.predefined_filter_saved_successfully'),
'tag' => 'predefinedFilter',
]);
} else {
$this->dispatch('showNotification', [
'type' => 'error',
'title' => trans('general.notification_error'),
'message' => trans('general.notification_error'),
'tag' => 'predefinedFilter',
]);
}

$this->dispatch("savePredefinedFiltersModalEvent");
$this->dispatch("closePredefinedFiltersModal");
}

#[On("updatePredefinedFiltersModal")]
public function updatePredefinedFiltersModal(
PredefinedFilterService $predefinedFilterService
) {
$this->validate([
'name' => 'required|string',
'filterData' => 'array',
'groupSelect' => 'array',
'groupSelect.*' => 'required|integer|exists:permission_groups,id',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really required? When you have a private filter, I don't think you need it.

]);

$predefinedFilter = PredefinedFilter::find($this->filterId);

$validated = [
'name' => $this->name ?? $predefinedFilter->name,
'filter_data' => $this->filterData ?? $predefinedFilter->filter_data,
'is_public' => isset($this->visibility)
? ($this->visibility === FilterVisibility::Public ? 1 : 0)
: $predefinedFilter->is_public,
'permissions' => self::formatPermissions($this->getGroupSelectArrayAsArray()),
];

$updateFilterResponse = $predefinedFilterService->updateFilter($predefinedFilter, $validated);

if ($updateFilterResponse === true) {
$this->dispatch('showNotification', [
'type' => 'success',
'title' => trans('general.notification_success'),
'message' => trans('general.predefined_filter_saved_successfully'),
'tag' => 'predefinedFilter',
]);
} else {
$this->dispatch('showNotification', [
'type' => 'error',
'title' => trans('general.notification_error'),
'message' => trans('general.notification_error'),
'tag' => 'predefinedFilter',
]);
}

$this->dispatch("updatePredefinedFiltersModalEvent");
$this->dispatch("closePredefinedFiltersModal");
}

#[On("deletePredefinedFiltersModal")]
public function deletePredefinedFiltersModal(
PredefinedFilterService $predefinedFilterService
) {


$predefinedFilter = $predefinedFilterService->getFilterById($this->filterId);
$deleteFilterResponse = $predefinedFilterService->deleteFilter($predefinedFilter);

if ($deleteFilterResponse === true) {
$this->dispatch('showNotification', [
'type' => 'success',
'title' => trans('general.notification_success'),
'message' => trans('general.predefined_filter_saved_successfully'),
'tag' => 'predefinedFilter',
]);
} else {
$this->dispatch('showNotification', [
'type' => 'error',
'title' => trans('general.notification_error'),
'message' => trans('general.notification_error'),
'tag' => 'predefinedFilter',
]);
}

$this->dispatch("deletePredefinedFiltersModalEvent");
$this->dispatch("closePredefinedFiltersModal");
}

public function updateGroupSelect($values)
{
$this->groupSelect = is_array($values)
? $values
: ($values
? [$values]
: []);
}

public function render()
{
return view("livewire.partials.advancedsearch.modal");
}

private function getGroupSelectArrayAsArray(): array
{
if (is_array($this->groupSelect) === true) {
return $this->groupSelect;
}
return [$this->groupSelect];
}

private static function formatPermissions(array $permissions): array
{
$result = [];

foreach ($permissions as $value) {
$result[] = ["permission_group_id" => $value];
}

return $result;
}
}
1 change: 0 additions & 1 deletion app/Services/PredefinedFilterPermissionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public function store(array $validated): PredefinedFilterPermission
$permission->predefined_filter_id = $validated['predefined_filter_id'];
$permission->permission_group_id = $validated['permission_group_id'];
$permission->created_by = $userId;

if (!$permission->save()) {
//dump($permission->getErrors());
throw new Exception($permission->getErrors());
Expand Down
57 changes: 26 additions & 31 deletions app/Services/PredefinedFilterService.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public function canUserViewFilter($filter): bool

public function createFilter($validated): PredefinedFilter
{
//dump($validated);
$filter_create_response = PredefinedFilter::create([
'name' => $validated['name'],
'filter_data' => $validated['filter_data'],
Expand All @@ -91,35 +90,32 @@ public function updateFilter(PredefinedFilter $filter, array $validated): Predef
'filter_data' => $validated['filter_data'],
'is_public' => $validated['is_public'],
]);

$filter->save();

// Update permissions
if (array_key_exists('permissions', $validated)) {
$currently_set_permssions = $this->predefinedFilterPermissionService->getPermissionsByPredefinedFilterId($filter->id);
$new_permissions = $validated['permissions'];
$permission_diff = $this->syncPermissions($currently_set_permssions->toArray(), $new_permissions);
//dump($permission_diff);

try {
DB::transaction(function () use ($permission_diff, $filter) {
if (!empty($permission_diff['to_delete'])) {
foreach ($permission_diff['to_delete'] as $permission) {
//dump($permission);
$this->predefinedFilterPermissionService->deletePermissionByFilterId($permission['predefined_filter_id']);
}
}

if (!empty($permission_diff['to_add'])) {
foreach ($permission_diff['to_add'] as $permission) {
$permission['predefined_filter_id'] = $filter->id;
//dump($permission);
$this->predefinedFilterPermissionService->store($permission);
}
}
});
} catch (Throwable $e) {
// If any exception occurs, the transaction is automatically rolled back.
//dump($e);
throw new Exception($e->getMessage());
//abort(500,message: "Something went wrong");
}
Expand All @@ -128,9 +124,9 @@ public function updateFilter(PredefinedFilter $filter, array $validated): Predef
return $filter;
}

public function deleteFilter(PredefinedFilter $filter): void
public function deleteFilter(PredefinedFilter $filter): ?bool
{
$filter->delete();
return $filter->delete();
}

public function selectList(Request $request): LengthAwarePaginator
Expand Down Expand Up @@ -169,30 +165,29 @@ public function selectList(Request $request): LengthAwarePaginator
return $paginated;
}

private function syncPermissions($currentPermissions, $newPermissions): array
{
// Calculate permissions to add
$toAdd = array_udiff(
$newPermissions,
$currentPermissions,
function ($obj_a, $obj_b) {
return $obj_a['permission_group_id'] !== $obj_b['permission_group_id'];
}
);

// Calculate permissions to delete
$toDelete = array_udiff(
$currentPermissions,
$newPermissions,
function ($obj_a, $obj_b) {
return $obj_a['permission_group_id'] !== $obj_b['permission_group_id'];
}
);
private function syncPermissions($currentPermissions, $newPermissions): array
{
$toAdd = array_udiff(
$newPermissions,
$currentPermissions,
function ($a, $b) {
return $a['permission_group_id'] <=> $b['permission_group_id'];
}
);

$toDelete = array_udiff(
$currentPermissions,
$newPermissions,
function ($a, $b) {
return $a['permission_group_id'] <=> $b['permission_group_id'];
}
);

return [
'to_add' => $toAdd,
'to_delete' => $toDelete
];
}

return [
'to_add' => $toAdd,
'to_delete' => $toDelete
];
}

}
1 change: 1 addition & 0 deletions resources/views/hardware/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
</button>
</div>

<livewire:partials.advancedsearch.modal />

<table data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}"
data-cookie-id-table="{{ request()->has('status') ? e(request()->input('status')) : '' }}assetsListingTable"
Expand Down
Loading
Loading