Skip to content

Commit 7f9c9af

Browse files
committed
NEXT
1 parent 104eb68 commit 7f9c9af

File tree

12 files changed

+640
-220
lines changed

12 files changed

+640
-220
lines changed

.claude/settings.local.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(find:*)",
5+
"Bash(composer:*)",
6+
"Bash(grep:*)",
7+
"Bash(rg:*)",
8+
"Bash(/usr/bin/grep -n -A 15 -B 5 \"recordActions.*foreach\" /Users/manuk/Herd/flowforge/vendor/filament/tables/resources/views/index.blade.php)"
9+
],
10+
"deny": []
11+
}
12+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
<x-filament-panels::page>
2-
Board Page
2+
@livewire('relaticle.flowforge.livewire.kanban-board', [
3+
'adapter' => $this->getAdapter(),
4+
'pageClass' => $this->getPageClass(),
5+
])
36
</x-filament-panels::page>

resources/views/livewire/card.blade.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
@props(['config', 'columnId', 'record'])
22

3+
@php
4+
$boardPage = app($this->pageClass);
5+
$recordActions = $boardPage instanceof \Relaticle\Flowforge\BoardPage ? $boardPage->getBoard()->getRecordActions() : [];
6+
$hasActions = !empty($recordActions);
7+
@endphp
8+
39
<div
410
@class([
511
'ff-card kanban-card',
6-
'ff-card--interactive' => $this->editAction() && ($this->editAction)(['record' => $record['id']])->isVisible(),
7-
'ff-card--non-interactive' => !$this->editAction()
12+
'ff-card--interactive' => $hasActions,
13+
'ff-card--non-interactive' => !$hasActions
814
])
915
x-sortable-handle
1016
x-sortable-item="{{ $record['id'] }}"
11-
@if($this->editAction() && ($this->editAction)(['record' => $record['id']])->isVisible())
12-
wire:click="mountAction('edit', {record: '{{ $record['id'] }}'})"
13-
@endif
1417
>
1518
<div class="ff-card__content">
1619
<h4 class="ff-card__title">{{ $record['title'] }}</h4>
@@ -38,4 +41,17 @@
3841
</div>
3942
@endif
4043
</div>
44+
45+
{{-- Render record actions --}}
46+
@if($hasActions)
47+
@php
48+
$processedRecordActions = $boardPage->getRecordActionsForRecord($record);
49+
@endphp
50+
51+
<div class="ff-card__actions">
52+
@foreach($processedRecordActions as $action)
53+
{{ $action }}
54+
@endforeach
55+
</div>
56+
@endif
4157
</div>

resources/views/livewire/column.blade.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,17 @@ class="ff-column kanban-column">
1313
</div>
1414
</div>
1515

16-
@if ($this->createAction() && ($this->createAction)(['column' => $columnId])->isVisible())
17-
{{ ($this->createAction)(['column' => $columnId]) }}
18-
@endif
16+
{{-- Render column actions --}}
17+
@php
18+
$boardPage = app($this->pageClass);
19+
$processedActions = $boardPage instanceof \Relaticle\Flowforge\BoardPage
20+
? $boardPage->getColumnActionsForColumn($columnId)
21+
: [];
22+
@endphp
23+
24+
@foreach($processedActions as $action)
25+
{{ $action }}
26+
@endforeach
1927
</div>
2028

2129
<!-- Column Content -->

src/Adapters/DefaultKanbanAdapter.php

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Relaticle\Flowforge\Adapters;
66

7-
use EloquentSerialize;
7+
use Closure;
88
use Illuminate\Database\Eloquent\Builder;
99
use Livewire\Wireable;
1010
use Relaticle\Flowforge\Concerns\CardFormattingTrait;
@@ -20,9 +20,19 @@ class DefaultKanbanAdapter implements KanbanAdapterInterface, Wireable
2020
use QueryHandlingTrait;
2121

2222
/**
23-
* The base Eloquent query builder.
23+
* The query closure that returns a fresh query builder.
2424
*/
25-
public Builder $baseQuery;
25+
protected Closure $queryCallback;
26+
27+
/**
28+
* The model class name for reconstruction.
29+
*/
30+
protected string $modelClass;
31+
32+
/**
33+
* The connection name for reconstruction.
34+
*/
35+
protected ?string $connectionName;
2636

2737
/**
2838
* Create a new abstract Kanban adapter instance.
@@ -31,7 +41,27 @@ public function __construct(
3141
Builder $query,
3242
public KanbanConfig $config
3343
) {
34-
$this->baseQuery = $query;
44+
$this->modelClass = get_class($query->getModel());
45+
$this->connectionName = $query->getModel()->getConnectionName();
46+
47+
// Store a closure that can recreate the query
48+
$this->queryCallback = fn() => $query->clone();
49+
}
50+
51+
/**
52+
* Get a fresh query builder instance.
53+
*/
54+
protected function getQuery(): Builder
55+
{
56+
return ($this->queryCallback)();
57+
}
58+
59+
/**
60+
* Get the base query (for backwards compatibility).
61+
*/
62+
public function getBaseQuery(): Builder
63+
{
64+
return $this->getQuery();
3565
}
3666

3767
/**
@@ -45,15 +75,25 @@ public function getConfig(): KanbanConfig
4575
public function toLivewire(): array
4676
{
4777
return [
48-
'query' => EloquentSerialize::serialize($this->baseQuery),
78+
'modelClass' => $this->modelClass,
79+
'connectionName' => $this->connectionName,
4980
'config' => $this->config,
5081
];
5182
}
5283

5384
public static function fromLivewire($value): static
5485
{
55-
$query = EloquentSerialize::unserialize($value['query']);
56-
86+
$modelClass = $value['modelClass'];
87+
$connectionName = $value['connectionName'];
88+
89+
// Recreate the query from the model class and connection
90+
$model = new $modelClass();
91+
if ($connectionName) {
92+
$model->setConnection($connectionName);
93+
}
94+
95+
$query = $model->newQuery();
96+
5797
return new static($query, $value['config']);
5898
}
5999
}

src/Board.php

Lines changed: 137 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,144 @@
22

33
namespace Relaticle\Flowforge;
44

5-
use Filament\Support\Components\ViewComponent;
6-
use Relaticle\Flowforge\Concerns\HasRecordAction;
7-
use Relaticle\Flowforge\Concerns\HasRecordActions;
5+
use Closure;
6+
use Filament\Actions\Action;
7+
use Filament\Actions\ActionGroup;
88

9-
class Board extends ViewComponent
9+
class Board
1010
{
11-
use HasRecordAction;
12-
use HasRecordActions;
1311

12+
protected ?string $recordTitleAttribute = null;
13+
14+
protected ?string $columnIdentifierAttribute = null;
15+
16+
protected ?array $defaultSort = null;
17+
18+
/**
19+
* @var Column[]
20+
*/
21+
protected array $columns = [];
22+
23+
/**
24+
* @var Action[]|ActionGroup[]
25+
*/
26+
protected array $columnActions = [];
27+
28+
protected array $recordProperties = [];
29+
30+
/**
31+
* @var Action[]|ActionGroup[]
32+
*/
33+
protected array $recordActions = [];
34+
35+
public function recordTitleAttribute(string $attribute): static
36+
{
37+
$this->recordTitleAttribute = $attribute;
38+
39+
return $this;
40+
}
41+
42+
public function columnIdentifierAttribute(string $attribute): static
43+
{
44+
$this->columnIdentifierAttribute = $attribute;
45+
46+
return $this;
47+
}
48+
49+
public function defaultSort(string $column, string $direction = 'asc'): static
50+
{
51+
$this->defaultSort = [
52+
'column' => $column,
53+
'direction' => $direction,
54+
];
55+
56+
return $this;
57+
}
58+
59+
/**
60+
* @param Column[] $columns
61+
*/
62+
public function columns(array $columns): static
63+
{
64+
$this->columns = $columns;
65+
66+
return $this;
67+
}
68+
69+
/**
70+
* @param Action[]|ActionGroup[] $actions
71+
*/
72+
public function columnActions(array $actions): static
73+
{
74+
$this->columnActions = $actions;
75+
76+
return $this;
77+
}
78+
79+
public function getRecordTitleAttribute(): ?string
80+
{
81+
return $this->recordTitleAttribute;
82+
}
83+
84+
public function getColumnIdentifierAttribute(): ?string
85+
{
86+
return $this->columnIdentifierAttribute;
87+
}
88+
89+
public function getDefaultSort(): ?array
90+
{
91+
return $this->defaultSort;
92+
}
93+
94+
/**
95+
* @return Column[]
96+
*/
97+
public function getColumns(): array
98+
{
99+
return $this->columns;
100+
}
101+
102+
/**
103+
* @param Property[] $properties
104+
*/
105+
public function recordProperties(array $properties): static
106+
{
107+
$this->recordProperties = $properties;
108+
109+
return $this;
110+
}
111+
112+
/**
113+
* @return Property[]
114+
*/
115+
public function getRecordProperties(): array
116+
{
117+
return $this->recordProperties;
118+
}
119+
120+
/**
121+
* @param Action[]|ActionGroup[] $actions
122+
*/
123+
public function recordActions(array $actions): static
124+
{
125+
$this->recordActions = $actions;
126+
127+
return $this;
128+
}
129+
130+
/**
131+
* @return Action[]|ActionGroup[]
132+
*/
133+
public function getColumnActions(): array
134+
{
135+
return $this->columnActions;
136+
}
137+
138+
/**
139+
* @return Action[]|ActionGroup[]
140+
*/
141+
public function getRecordActions(): array
142+
{
143+
return $this->recordActions;
144+
}
14145
}

0 commit comments

Comments
 (0)