Skip to content

Commit e38d0d4

Browse files
committed
UPP_21
1 parent 0eb7393 commit e38d0d4

File tree

8 files changed

+189
-538
lines changed

8 files changed

+189
-538
lines changed

resources/views/filament/pages/kanban-board-page.blade.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<div class="h-[calc(100vh-12rem)]">
33
@livewire('relaticle.flowforge.livewire.kanban-board', [
44
'adapter' => $this->getAdapter(),
5+
'pageClass' => $this::class
56
])
67
</div>
78
</x-filament::page>

src/Adapters/AbstractKanbanAdapter.php

Lines changed: 164 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,158 @@
44

55
namespace Relaticle\Flowforge\Adapters;
66

7-
use App\Models\Task;
87
use Filament\Forms\Form;
8+
use Illuminate\Database\Eloquent\Builder;
99
use Illuminate\Database\Eloquent\Model;
1010
use Illuminate\Support\Collection;
1111
use Livewire\Wireable;
1212
use Relaticle\Flowforge\Config\KanbanConfig;
1313
use Relaticle\Flowforge\Contracts\KanbanAdapterInterface;
1414

15-
/**
16-
* Abstract implementation of the Kanban adapter interface.
17-
*
18-
* This class provides shared functionality for all Eloquent-based Kanban adapters,
19-
* including configuration management and common form building logic.
20-
*/
2115
abstract class AbstractKanbanAdapter implements KanbanAdapterInterface, Wireable
2216
{
17+
/**
18+
* The base Eloquent query builder.
19+
*
20+
* @var Builder
21+
*/
22+
public Builder $baseQuery;
23+
2324
/**
2425
* Create a new abstract Kanban adapter instance.
2526
*/
2627
public function __construct(
27-
protected readonly KanbanConfig $config
28+
Builder $query,
29+
public KanbanConfig $config
2830
) {
2931
}
3032

33+
/**
34+
* Get a new query builder, cloned from the base query.
35+
*/
36+
protected function newQuery(): Builder
37+
{
38+
return clone $this->baseQuery;
39+
}
40+
41+
/**
42+
* Find a model by its ID.
43+
*
44+
* @param mixed $id The model ID
45+
*/
46+
public function getModelById(mixed $id): ?Model
47+
{
48+
// Just find by ID without additional filters from the base query
49+
// This ensures we can find models by ID regardless of the base query filters
50+
return $this->baseQuery->getModel()::query()->find($id);
51+
}
52+
53+
/**
54+
* Get all items for the Kanban board.
55+
*/
56+
public function getItems(): Collection
57+
{
58+
$query = $this->newQuery();
59+
$orderField = $this->config->getOrderField();
60+
61+
if ($orderField !== null) {
62+
$query->orderBy($orderField);
63+
}
64+
65+
$models = $query->get();
66+
67+
return $this->formatCardsForDisplay($models);
68+
}
69+
70+
/**
71+
* Get items for a specific column with pagination.
72+
*
73+
* @param string|int $columnId The column ID
74+
* @param int $limit The number of items to return
75+
*/
76+
public function getItemsForColumn(string|int $columnId, int $limit = 10): Collection
77+
{
78+
$columnField = $this->config->getColumnField();
79+
$orderField = $this->config->getOrderField();
80+
81+
$query = $this->newQuery()->where($columnField, $columnId);
82+
83+
if ($orderField !== null) {
84+
$query->orderBy($orderField);
85+
}
86+
87+
$models = $query->limit($limit)->get();
88+
89+
return $this->formatCardsForDisplay($models);
90+
}
91+
92+
/**
93+
* Get the total count of items for a specific column.
94+
*
95+
* @param string|int $columnId The column ID
96+
*/
97+
public function getColumnItemsCount(string|int $columnId): int
98+
{
99+
$columnField = $this->config->getColumnField();
100+
101+
return $this->newQuery()
102+
->where($columnField, $columnId)
103+
->count();
104+
}
105+
106+
/**
107+
* Create a new card with the given attributes.
108+
*
109+
* @param array<string, mixed> $attributes The card attributes
110+
*/
111+
public function createCard(array $attributes): ?Model
112+
{
113+
$model = $this->baseQuery->getModel()->newInstance();
114+
115+
// Apply any scopes from the base query if applicable
116+
// For example, if the base query filters by user_id, we want to set that on the new model
117+
$wheres = $this->baseQuery->getQuery()->wheres;
118+
119+
foreach ($wheres as $where) {
120+
if (isset($where['column']) && isset($where['value']) && $where['type'] === 'Basic') {
121+
// If the filter is a basic where clause, apply it to the new model
122+
// This ensures models created through this adapter respect the base query conditions
123+
$model->{$where['column']} = $where['value'];
124+
}
125+
}
126+
127+
$model->fill($attributes);
128+
129+
if ($model->save()) {
130+
return $model;
131+
}
132+
133+
return null;
134+
}
135+
136+
/**
137+
* Update an existing card with the given attributes.
138+
*
139+
* @param Model $card The card to update
140+
* @param array<string, mixed> $attributes The card attributes to update
141+
*/
142+
public function updateCard(Model $card, array $attributes): bool
143+
{
144+
$card->fill($attributes);
145+
146+
return $card->save();
147+
}
148+
149+
/**
150+
* Delete an existing card.
151+
*
152+
* @param Model $card The card to delete
153+
*/
154+
public function deleteCard(Model $card): bool
155+
{
156+
return $card->delete();
157+
}
158+
31159
/**
32160
* Get the configuration for this adapter.
33161
*/
@@ -44,17 +172,9 @@ public function getConfig(): KanbanConfig
44172
*/
45173
public function getCreateForm(Form $form, mixed $activeColumn): Form
46174
{
47-
// Check for custom create form callback
48-
$createCallback = $this->config->getCreateFormCallback();
49-
50-
if ($createCallback !== null && is_callable($createCallback)) {
51-
return $createCallback($form, $activeColumn);
52-
}
53-
54175
// Fall back to default create form implementation
55176
$titleField = $this->config->getTitleField();
56177
$descriptionField = $this->config->getDescriptionField();
57-
$columnField = $this->config->getColumnField();
58178

59179
$schema = KanbanConfig::getDefaultCreateFormSchema($titleField, $descriptionField);
60180

@@ -74,20 +194,6 @@ public function getCreateForm(Form $form, mixed $activeColumn): Form
74194
*/
75195
public function getEditForm(Form $form): Form
76196
{
77-
// Check for custom edit form callback
78-
$editCallback = $this->config->getEditFormCallback();
79-
80-
if ($editCallback !== null && is_callable($editCallback)) {
81-
return $editCallback($form);
82-
}
83-
84-
// Check for custom create form callback as a fallback
85-
$createCallback = $this->config->getCreateFormCallback();
86-
87-
if ($createCallback !== null && is_callable($createCallback)) {
88-
return $createCallback($form, null);
89-
}
90-
91197
// Fall back to default edit form implementation
92198
$titleField = $this->config->getTitleField();
93199
$descriptionField = $this->config->getDescriptionField();
@@ -182,4 +288,32 @@ public function updateCardsOrderAndColumn(string|int $columnId, array $cardIds):
182288

183289
return $success;
184290
}
291+
292+
293+
/**
294+
* Convert the adapter to a Livewire-compatible array.
295+
*
296+
* @return array<string, mixed>
297+
*/
298+
public function toLivewire(): array
299+
{
300+
return [
301+
'query' => \EloquentSerialize::serialize($this->baseQuery),
302+
'config' => $this->config->toArray(),
303+
];
304+
}
305+
306+
/**
307+
* Create a new adapter instance from a Livewire-compatible array.
308+
*
309+
* @param array<string, mixed> $value The Livewire-compatible array
310+
* @return static
311+
*/
312+
public static function fromLivewire($value): static
313+
{
314+
$query = \EloquentSerialize::unserialize($value['query']);
315+
$config = new KanbanConfig(...$value['config']);
316+
317+
return new static($query, $config);
318+
}
185319
}

0 commit comments

Comments
 (0)