Skip to content

Commit 104eb68

Browse files
committed
Next Init
1 parent 2cf5b82 commit 104eb68

File tree

6 files changed

+480
-0
lines changed

6 files changed

+480
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<x-filament-panels::page>
2+
Board Page
3+
</x-filament-panels::page>

src/Board.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Relaticle\Flowforge;
4+
5+
use Filament\Support\Components\ViewComponent;
6+
use Relaticle\Flowforge\Concerns\HasRecordAction;
7+
use Relaticle\Flowforge\Concerns\HasRecordActions;
8+
9+
class Board extends ViewComponent
10+
{
11+
use HasRecordAction;
12+
use HasRecordActions;
13+
14+
}

src/BoardPage.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Relaticle\Flowforge;
4+
5+
use Filament\Pages\Page;
6+
7+
class BoardPage extends Page
8+
{
9+
protected string $view = 'flowforge::filament.pages.board-page';
10+
}

src/Column.php

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
3+
namespace Relaticle\Flowforge;
4+
5+
use Exception;
6+
use Filament\Actions\Action;
7+
use Filament\Support\Components\ViewComponent;
8+
use Filament\Support\Concerns\CanAggregateRelatedModels;
9+
use Filament\Support\Concerns\CanGrow;
10+
use Filament\Support\Concerns\CanSpanColumns;
11+
use Filament\Support\Concerns\CanWrapHeader;
12+
use Filament\Support\Concerns\HasAlignment;
13+
use Filament\Support\Concerns\HasCellState;
14+
use Filament\Support\Concerns\HasExtraAttributes;
15+
use Filament\Support\Concerns\HasPlaceholder;
16+
use Filament\Support\Concerns\HasVerticalAlignment;
17+
use Filament\Support\Concerns\HasWidth;
18+
use Filament\Support\Enums\Alignment;
19+
use Filament\Tables\Table;
20+
use Illuminate\Database\Eloquent\Model;
21+
use Illuminate\Support\HtmlString;
22+
use Illuminate\View\ComponentAttributeBag;
23+
24+
use function Filament\Support\generate_href_html;
25+
26+
class Column extends ViewComponent
27+
{
28+
use CanAggregateRelatedModels;
29+
use CanGrow;
30+
use CanSpanColumns;
31+
use CanWrapHeader;
32+
use HasAlignment;
33+
use HasCellState;
34+
use HasExtraAttributes;
35+
use HasPlaceholder;
36+
use HasVerticalAlignment;
37+
use HasWidth;
38+
39+
protected string $evaluationIdentifier = 'column';
40+
41+
protected string $viewIdentifier = 'column';
42+
43+
final public function __construct(string $name)
44+
{
45+
$this->name($name);
46+
}
47+
48+
public static function make(?string $name = null): static
49+
{
50+
$columnClass = static::class;
51+
52+
$name ??= static::getDefaultName();
53+
54+
if (blank($name)) {
55+
throw new Exception("Column of class [$columnClass] must have a unique name, passed to the [make()] method.");
56+
}
57+
58+
$static = app($columnClass, ['name' => $name]);
59+
$static->configure();
60+
61+
return $static;
62+
}
63+
64+
public static function getDefaultName(): ?string
65+
{
66+
return null;
67+
}
68+
69+
public function getTable(): Table
70+
{
71+
return $this->table ?? $this->getGroup()?->getTable() ?? $this->getLayout()?->getTable() ?? throw new Exception("The column [{$this->getName()}] is not mounted to a table.");
72+
}
73+
74+
/**
75+
* @return array<mixed>
76+
*/
77+
protected function resolveDefaultClosureDependencyForEvaluationByName(string $parameterName): array
78+
{
79+
return match ($parameterName) {
80+
'livewire' => [$this->getLivewire()],
81+
'record' => [$this->getRecord()],
82+
'rowLoop' => [$this->getRowLoop()],
83+
'state' => [$this->getState()],
84+
'table' => [$this->getTable()],
85+
default => parent::resolveDefaultClosureDependencyForEvaluationByName($parameterName),
86+
};
87+
}
88+
89+
/**
90+
* @return array<mixed>
91+
*/
92+
protected function resolveDefaultClosureDependencyForEvaluationByType(string $parameterType): array
93+
{
94+
$record = $this->getRecord();
95+
96+
if (! $record) {
97+
return parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType);
98+
}
99+
100+
if (! ($record instanceof Model)) {
101+
return parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType);
102+
}
103+
104+
return match ($parameterType) {
105+
Model::class, $record::class => [$record],
106+
default => parent::resolveDefaultClosureDependencyForEvaluationByType($parameterType),
107+
};
108+
}
109+
110+
public function renderInLayout(): ?HtmlString
111+
{
112+
if ($this->isHidden()) {
113+
return null;
114+
}
115+
116+
$attributes = (new ComponentAttributeBag)
117+
->gridColumn(
118+
$this->getColumnSpan(),
119+
$this->getColumnStart(),
120+
)
121+
->class([
122+
'fi-growable' => $this->canGrow(),
123+
(filled($hiddenFrom = $this->getHiddenFrom()) ? "{$hiddenFrom}:fi-hidden" : ''),
124+
(filled($visibleFrom = $this->getVisibleFrom()) ? "{$visibleFrom}:fi-visible" : ''),
125+
]);
126+
127+
$this->inline();
128+
129+
$action = $this->getAction();
130+
$url = $this->getUrl();
131+
$isClickDisabled = $this->isClickDisabled();
132+
133+
$wrapperTag = match (true) {
134+
$url && (! $isClickDisabled) => 'a',
135+
$action && (! $isClickDisabled) => 'button',
136+
default => 'div',
137+
};
138+
139+
$attributes = $attributes
140+
->merge([
141+
'type' => ($wrapperTag === 'button') ? 'button' : null,
142+
'wire:click' => $wireClickAction = match (true) {
143+
($wrapperTag !== 'button') => null,
144+
$action instanceof Action => "mountTableAction('{$action->getName()}', '{$this->getRecordKey()}')",
145+
filled($action) => "callTableColumnAction('{$this->getName()}', '{$this->getRecordKey()}')",
146+
default => null,
147+
},
148+
'wire:loading.attr' => ($wrapperTag === 'button') ? 'disabled' : null,
149+
'wire:target' => $wireClickAction,
150+
], escape: false)
151+
->class([
152+
'fi-ta-col',
153+
((($alignment = $this->getAlignment()) instanceof Alignment) ? "fi-align-{$alignment->value}" : (is_string($alignment) ? $alignment : '')),
154+
'fi-ta-col-has-column-url' => ($wrapperTag === 'a') && filled($url),
155+
]);
156+
157+
ob_start(); ?>
158+
159+
<<?= $wrapperTag ?>
160+
<?php if ($wrapperTag === 'a') {
161+
echo generate_href_html($url, $this->shouldOpenUrlInNewTab())->toHtml();
162+
} ?>
163+
<?= $attributes->toHtml() ?>
164+
>
165+
<?= $this->toHtml() ?>
166+
</<?= $wrapperTag ?>>
167+
168+
<?php return new HtmlString(ob_get_clean());
169+
}
170+
}

src/Concerns/HasRecordAction.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Relaticle\Flowforge\Concerns;
4+
5+
use Closure;
6+
use Filament\Actions\Action;
7+
use Illuminate\Database\Eloquent\Model;
8+
9+
trait HasRecordAction
10+
{
11+
protected string | Closure | null $recordAction = null;
12+
13+
public function recordAction(string | Closure | null $action): static
14+
{
15+
$this->recordAction = $action;
16+
17+
return $this;
18+
}
19+
20+
/**
21+
* @param Model | array<string, mixed> $record
22+
*/
23+
public function getRecordAction(Model | array $record): ?string
24+
{
25+
$action = $this->evaluate(
26+
$this->recordAction,
27+
namedInjections: [
28+
'record' => $record,
29+
],
30+
typedInjections: $record instanceof Model ? [
31+
Model::class => $record,
32+
$record::class => $record,
33+
] : [],
34+
);
35+
36+
if (! $action) {
37+
return null;
38+
}
39+
40+
if (! class_exists($action)) {
41+
return $action;
42+
}
43+
44+
if (! is_subclass_of($action, Action::class)) {
45+
return $action;
46+
}
47+
48+
return $action::getDefaultName() ?? $action;
49+
}
50+
}

0 commit comments

Comments
 (0)