Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('pim_property_value', function (Blueprint $table) {
$table->boolean('is_group')->default(false)->after('image');

$table->foreignId('group_value_id')
->nullable()
->after('is_group')
->constrained('pim_property_value')
->nullOnDelete();
});
}

public function down(): void
{
Schema::table('pim_property_value', function (Blueprint $table) {
$table->dropConstrainedForeignId('group_value_id');
$table->dropColumn('is_group');
});
}
};
27 changes: 27 additions & 0 deletions resources/lang/en/property-value.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
'table' => [
'columns' => [
'value' => 'Value',
'group' => 'Group',
'aliases' => 'Aliases',
'image' => 'Image',
'info_url' => 'Info URL',
'sort' => 'Sort',
Expand All @@ -45,6 +47,8 @@
'edit' => 'Edit',
'delete' => 'Delete',
'merge' => 'Merge…',
'group_aliases' => 'Group (aliases)',
'remove_from_group' => 'Remove from group',
],
],

Expand Down Expand Up @@ -76,6 +80,21 @@
'merged_error_body' => 'We couldn’t merge these values. Please try again.',
],

'grouping' => [
'success_grouped_title' => 'Grouped',
'success_grouped_body' => ':count value(s) grouped under ":target".',
'success_ungrouped_title' => 'Updated',
'success_ungrouped_body' => ':count value(s) removed from group.',
'error_title' => 'Grouping failed',
'selected_values' => 'Selected values',
'helper_target' => 'Choose the target value into which the selected values will be grouped.',
'errors' => [
'target_in_sources' => 'The target cannot be one of the selected values.',
'target_is_member' => 'The selected target already belongs to another group.',
'different_property' => 'All selected values and the target must belong to the same property.',
],
],

'pages' => [
'title' => [
'with_property' => 'Values for: :property',
Expand All @@ -87,6 +106,14 @@
],
],

'ui' => [
'group_badge' => 'Group',
],

'modal_grouping' => [
'target_label' => 'Target value',
],

'notifications' => [
'import_queued' => [
'title' => 'Import Queued',
Expand Down
27 changes: 27 additions & 0 deletions resources/lang/sl/property-value.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
'table' => [
'columns' => [
'value' => 'Vrednost',
'group' => 'Skupina',
'aliases' => 'Aliasi',
'image' => 'Slika',
'info_url' => 'URL informacij',
'sort' => 'Vrstni red',
Expand All @@ -45,6 +47,8 @@
'edit' => 'Uredi',
'delete' => 'Izbriši',
'merge' => 'Združi…',
'group_aliases' => 'Združi (aliase)',
'remove_from_group' => 'Odstrani iz skupine',
],
],

Expand Down Expand Up @@ -76,6 +80,21 @@
'merged_error_body' => 'Vrednosti trenutno ni mogoče združiti. Poskusite znova.',
],

'grouping' => [
'success_grouped_title' => 'Združeno',
'success_grouped_body' => ':count vrednost(i) združene pod ":target".',
'success_ungrouped_title' => 'Posodobljeno',
'success_ungrouped_body' => ':count vrednost(i) odstranjene iz skupine.',
'error_title' => 'Združevanje ni uspelo',
'selected_values' => 'Izbrane vrednosti',
'helper_target' => 'Izberite ciljno vrednost, v katero bodo združene izbrane vrednosti.',
'errors' => [
'target_in_sources' => 'Cilj ne sme biti med izbranimi vrednostmi.',
'target_is_member' => 'Izbrani cilj že pripada drugi skupini.',
'different_property' => 'Vse izbrane vrednosti in cilj morajo pripadati isti lastnosti.',
],
],

'pages' => [
'title' => [
'with_property' => 'Vrednosti za: :property',
Expand All @@ -87,6 +106,14 @@
],
],

'ui' => [
'group_badge' => 'Skupina',
],

'modal_grouping' => [
'target_label' => 'Ciljna vrednost',
],

'notifications' => [
'import_queued' => [
'title' => 'Uvoz v čakalni vrsti',
Expand Down
24 changes: 24 additions & 0 deletions resources/views/filament/bulk/group-selected-preview.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@php($items = $getState() ?? [])

<div class="space-y-3 max-h-72 overflow-auto">
<div class="text-sm font-medium">
{{ __('eclipse-catalogue::property-value.grouping.selected_values') }}
</div>
<ul class="ms-1 space-y-2">
@foreach($items as $record)
<li>
<div class="flex flex-wrap items-center gap-2">
<span class="text-gray-400 select-none">-</span>
<span class="font-medium">{{ is_array($record) ? ($record['value'] ?? '') : ($record->value ?? '') }}</span>
@if(is_array($record) ? ($record['is_group'] ?? false) : ($record->is_group ?? false))
<x-filament::badge color="primary" class="!inline-flex !w-auto !px-2 !py-0.5">{{ __('eclipse-catalogue::property-value.ui.group_badge') }}</x-filament::badge>
@elseif(is_array($record) ? !empty($record['group_value'] ?? null) : !empty(optional($record->group)->value))
<x-filament::badge color="warning" class="!inline-flex !w-auto !px-2 !py-0.5">{{ is_array($record) ? ($record['group_value'] ?? '') : (optional($record->group)->value ?? '') }}</x-filament::badge>
@endif
</div>
</li>
@endforeach
</ul>
</div>


18 changes: 18 additions & 0 deletions resources/views/filament/columns/group-and-aliases.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@php($rec = $getRecord())

<div class="flex flex-wrap items-center gap-1">
@if($rec->is_group)
<x-filament::badge color="primary">{{ __('eclipse-catalogue::property-value.ui.group_badge') }}</x-filament::badge>
@endif

@if($rec->group)
<x-filament::badge color="warning">{{ $rec->group->value }}</x-filament::badge>
@endif

@php($aliases = $rec->members()->count())
@if($rec->is_group)
<x-filament::badge color="gray">{{ $aliases }}</x-filament::badge>
@endif
</div>


129 changes: 123 additions & 6 deletions src/Filament/Resources/PropertyValueResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Eclipse\Catalogue\Values\Background;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
Expand All @@ -28,14 +29,16 @@
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Group;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\View as SchemaView;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ViewColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
use LaraZeus\SpatieTranslatable\Resources\Concerns\Translatable;
use Log;
use Throwable;

class PropertyValueResource extends Resource
Expand Down Expand Up @@ -119,6 +122,11 @@ public static function table(Table $table): Table
->searchable()
->sortable(),

ViewColumn::make('group_and_aliases')
->label(__('eclipse-catalogue::property-value.table.columns.group'))
->view('eclipse-catalogue::filament.columns.group-and-aliases')
->extraAttributes(['class' => 'space-x-1']),

TextColumn::make('color_swatch')
->label('Color')
->state(fn ($record) => $record->getColor())
Expand Down Expand Up @@ -254,6 +262,115 @@ public static function table(Table $table): Table
])
->toolbarActions([
BulkActionGroup::make([
BulkAction::make('group_values')
->label(__('eclipse-catalogue::property-value.table.actions.group_aliases'))
->icon('heroicon-o-rectangle-group')
->form(function (\Filament\Actions\BulkAction $action) {
$firstRecord = $action->getSelectedRecords()->first();
$derivedPropertyId = $firstRecord?->property_id ?? (request()->has('property') ? (int) request('property') : null);

return [
SchemaView::make('eclipse-catalogue::filament.bulk.group-selected-preview')
->statePath('selected_records')
->dehydrated(false)
->afterStateHydrated(function ($component) use ($action) {
$records = $action->getSelectedRecordsQuery()->with(['group:id,value'])->get();
$items = $records->map(function (PropertyValue $record) {
return [
'id' => $record->id,
'value' => $record->value,
'is_group' => (bool) $record->is_group,
'group_value' => $record->group?->value,
];
})->all();
$component->state($items);
})
->columnSpanFull(),

Hidden::make('property_id')
->default($derivedPropertyId),

Select::make('target_id')
->label(__('eclipse-catalogue::property-value.modal_grouping.target_label'))
->helperText(__('eclipse-catalogue::property-value.grouping.helper_target'))
->required()
->options(function (Get $get) {
$query = PropertyValue::query();
$propertyId = $get('property_id');
if ($propertyId) {
$query->sameProperty((int) $propertyId);
}

return $query->orderBy('value')->pluck('value', 'id');
})
->searchable(),
];
})
->action(function (\Illuminate\Support\Collection $records, array $data) {
try {
if ($records->isEmpty()) {
return;
}

$target = PropertyValue::findOrFail((int) $data['target_id']);

$sourceIds = $records->pluck('id');
if ($sourceIds->contains($target->id)) {
Notification::make()->title(__('eclipse-catalogue::property-value.grouping.error_title'))->body(__('eclipse-catalogue::property-value.grouping.errors.target_in_sources'))->danger()->send();

return;
}

if ($target->group_value_id !== null) {
Notification::make()->title(__('eclipse-catalogue::property-value.grouping.error_title'))->body(__('eclipse-catalogue::property-value.grouping.errors.target_is_member'))->danger()->send();

return;
}

$updated = 0;
foreach ($records as $record) {
/** @var PropertyValue $source */
$source = $record instanceof PropertyValue ? $record : PropertyValue::findOrFail($record);
if ($source->property_id !== $target->property_id) {
Notification::make()->title(__('eclipse-catalogue::property-value.grouping.error_title'))->body(__('eclipse-catalogue::property-value.grouping.errors.different_property'))->danger()->send();

return;
}
$source->groupInto($target->id);
$updated++;
}

Notification::make()->title(__('eclipse-catalogue::property-value.grouping.success_grouped_title'))
->body(__('eclipse-catalogue::property-value.grouping.success_grouped_body', ['count' => $updated, 'target' => $target->value]))
->success()->send();
} catch (\Throwable $e) {
Log::error('Bulk group failed', ['exception' => $e]);
Notification::make()->title(__('eclipse-catalogue::property-value.grouping.error_title'))->body(__('eclipse-catalogue::property-value.messages.merged_error_body'))->danger()->send();
}
})
->deselectRecordsAfterCompletion(),

BulkAction::make('ungroup_values')
->label(__('eclipse-catalogue::property-value.table.actions.remove_from_group'))
->icon('heroicon-o-squares-2x2')
->action(function (\Illuminate\Support\Collection $records) {
try {
$updated = 0;
foreach ($records as $record) {
/** @var PropertyValue $model */
$model = $record instanceof PropertyValue ? $record : PropertyValue::findOrFail($record);
$model->removeFromGroup();
$updated++;
}
Notification::make()->title(__('eclipse-catalogue::property-value.grouping.success_ungrouped_title'))
->body(__('eclipse-catalogue::property-value.grouping.success_ungrouped_body', ['count' => $updated]))
->success()->send();
} catch (\Throwable $e) {
Log::error('Bulk ungroup failed', ['exception' => $e]);
Notification::make()->title(__('eclipse-catalogue::property-value.grouping.error_title'))->body(__('eclipse-catalogue::property-value.messages.merged_error_body'))->danger()->send();
}
})
->deselectRecordsAfterCompletion(),
DeleteBulkAction::make(),
]),
]);
Expand Down Expand Up @@ -284,11 +401,11 @@ public static function buildColorGroupSchema(): array
->default(BackgroundType::NONE->value)
->live(),
ColorPicker::make('color')
->visible(fn (Get $get) => $get('type') === 's')
->visible(fn (\Filament\Schemas\Components\Utilities\Get $get) => $get('type') === 's')
->live(),
Grid::make()
->columns(4)
->visible(fn (Get $get) => $get('type') === 'g')
->visible(fn (\Filament\Schemas\Components\Utilities\Get $get) => $get('type') === 'g')
->schema([
ColorPicker::make('color_start')->columnSpan(2)->live(),
ColorPicker::make('color_end')->columnSpan(2)->live(),
Expand All @@ -309,7 +426,7 @@ public static function buildColorGroupSchema(): array
]),
ViewField::make('preview')
->view('eclipse-catalogue::components.color-preview')
->visible(function (Get $get) {
->visible(function (\Filament\Schemas\Components\Utilities\Get $get) {
$bg = Background::fromForm([
'type' => $get('type'),
'color' => $get('color'),
Expand All @@ -321,7 +438,7 @@ public static function buildColorGroupSchema(): array

return $bg->hasRenderableCss();
})
->viewData(function (Get $get) {
->viewData(function (\Filament\Schemas\Components\Utilities\Get $get) {
$bg = Background::fromForm([
'type' => $get('type'),
'color' => $get('color'),
Expand Down Expand Up @@ -365,6 +482,6 @@ public static function getEloquentQuery(): Builder
$query->where('property_id', request('property'));
}

return $query;
return $query->with(['group', 'members'])->groupedOrder();
}
}
Loading