mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Merge branch 'feature/theming' of github.com:laravel-filament/filament into feature/theming
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"/js/filament.js": "/js/filament.js?id=a3029b69d87820f78653",
|
||||
"/css/filament.css": "/css/filament.css?id=aeaa524e8752927a70a9"
|
||||
"/css/filament.css": "/css/filament.css?id=258be1ef621afe17391c"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'dateTimePicker' => [
|
||||
|
||||
'abbreviatedDays' => [
|
||||
'friday' => 'Jum',
|
||||
'monday' => 'Sen',
|
||||
'saturday' => 'Sab',
|
||||
'sunday' => 'Min',
|
||||
'thursday' => 'Kam',
|
||||
'tuesday' => 'Sel',
|
||||
'wednesday' => 'Rab',
|
||||
],
|
||||
|
||||
'months' => [
|
||||
'april' => 'April',
|
||||
'august' => 'Agustus',
|
||||
'december' => 'Desember',
|
||||
'february' => 'Februari',
|
||||
'january' => 'Januari',
|
||||
'july' => 'Juli',
|
||||
'june' => 'Juni',
|
||||
'march' => 'Maret',
|
||||
'may' => 'Mei',
|
||||
'november' => 'November',
|
||||
'october' => 'Oktober',
|
||||
'september' => 'September',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'multiSelect' => [
|
||||
'emptyOptionsMessage' => 'Tidak ada opsi yang bisa dipilih.',
|
||||
'noSearchResultsMessage' => 'Tidak ada opsi yang sesuai pencarian anda.',
|
||||
'placeholder' => 'Pilih Opsi',
|
||||
],
|
||||
|
||||
'richEditor' => [
|
||||
|
||||
'dialogs' => [
|
||||
|
||||
'link' => [
|
||||
|
||||
'buttons' => [
|
||||
'link' => 'Tautan',
|
||||
'unlink' => 'Batalkan tautan',
|
||||
],
|
||||
|
||||
'label' => 'Tautan',
|
||||
|
||||
'placeholder' => 'Masukkan tautan',
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'toolbarButtons' => [
|
||||
'attachFiles' => 'Lampirkan File',
|
||||
'bold' => 'Bold',
|
||||
'bullet' => 'Bullet',
|
||||
'code' => 'Kode',
|
||||
'heading' => 'Judul',
|
||||
'italic' => 'Italic',
|
||||
'link' => 'Tautan',
|
||||
'number' => 'Nomor',
|
||||
'quote' => 'Quote',
|
||||
'redo' => 'Redo',
|
||||
'strike' => 'Coret',
|
||||
'subheading' => 'Anak judul',
|
||||
'title' => 'Judul',
|
||||
'undo' => 'Undo',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'select' => [
|
||||
'emptyOptionsMessage' => 'Mulai mengetik untuk mencari...',
|
||||
'noSearchResultsMessage' => 'Tidak ada opsi yang sesuai pencarian anda.',
|
||||
'placeholder' => 'Pilih salah satu opsi',
|
||||
],
|
||||
|
||||
'tags' => [
|
||||
'placeholder' => 'Tag baru',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -262,7 +262,7 @@ class Component
|
||||
{
|
||||
$this->record = $record;
|
||||
|
||||
if ($this->record) {
|
||||
if ($this->record instanceof Model) {
|
||||
$this->model(get_class($this->record));
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ class Component
|
||||
}
|
||||
|
||||
if ($shouldExecuteCallback) {
|
||||
$callback($this);
|
||||
$callback($this, $this->record);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ class Component
|
||||
}
|
||||
|
||||
if ($shouldExecuteCallback) {
|
||||
$callback($this);
|
||||
$callback($this, $this->record);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
||||
@@ -40,12 +40,6 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
'record' => [
|
||||
'button' => [
|
||||
'label' => 'Bearbeiten',
|
||||
],
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Suche',
|
||||
],
|
||||
|
||||
@@ -50,14 +50,6 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'record' => [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Edit',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Search',
|
||||
],
|
||||
|
||||
@@ -50,14 +50,6 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'record' => [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Editar',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Buscar',
|
||||
],
|
||||
|
||||
@@ -50,14 +50,6 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'record' => [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Modifier',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Rechercher',
|
||||
],
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
'goToPage' => 'Ke halaman :page',
|
||||
'next' => 'Selanjutnya',
|
||||
'previous' => 'Sebelumnya',
|
||||
],
|
||||
|
||||
'label' => 'Navigasi halaman',
|
||||
|
||||
'overview' => [
|
||||
'Menampilkan',
|
||||
'sampai',
|
||||
'dari',
|
||||
'hasil',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'delete' => [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Hapus yang dipilih',
|
||||
],
|
||||
|
||||
'modal' => [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'cancel' => [
|
||||
'label' => 'Batalkan',
|
||||
],
|
||||
|
||||
'delete' => [
|
||||
'label' => 'Hapus yang terpilih',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'description' => 'Apakah anda yakin ingin menghapus data yang dipilih? Aksi ini tidak bisa dibatalkan..',
|
||||
|
||||
'heading' => 'Hapus data yang dipilih?',
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'filter' => [
|
||||
'placeholder' => 'Filter',
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
'noRecords' => 'Data tidak ditemukan',
|
||||
],
|
||||
|
||||
'pagination' => [
|
||||
|
||||
'fields' => [
|
||||
|
||||
'recordsPerPage' => [
|
||||
'label' => 'per halaman',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Cari',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -50,14 +50,6 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'record' => [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Modifica',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Cerca',
|
||||
],
|
||||
|
||||
@@ -41,12 +41,6 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
'record' => [
|
||||
'button' => [
|
||||
'label' => 'Bewerk',
|
||||
],
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Zoeken',
|
||||
],
|
||||
|
||||
@@ -50,14 +50,6 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'record' => [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Editar',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'search' => [
|
||||
'placeholder' => 'Procurar',
|
||||
],
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<div {{ $attributes->merge(['class' => 'space-y-4']) }}>
|
||||
<div class="items-center justify-between space-y-4 sm:flex sm:space-y-0">
|
||||
<x-tables::delete-selected :selected="$selected" />
|
||||
<x-tables::delete-selected :disabled="count($selected) === 0" />
|
||||
|
||||
<x-tables::filter :table="$table" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@props([
|
||||
'selected' => [],
|
||||
'disabled' => true,
|
||||
])
|
||||
|
||||
<span
|
||||
@@ -18,10 +18,10 @@
|
||||
x-cloak
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
x-on:click="open = true"
|
||||
{!! count($selected) === 0 ? 'disabled' : null !!}
|
||||
class="{{ count($selected) === 0 ? 'opacity-25 cursor-not-allowed' : 'cursor-pointer' }} font-medium border rounded transition duration-200 shadow-sm focus:ring focus:ring-opacity-50 text-sm py-2 px-4 border-transparent bg-danger-600 text-white hover:bg-danger-700 focus:ring-danger-200"
|
||||
type="button"
|
||||
x-on:click="open = true"
|
||||
{!! $disabled ? 'disabled' : null !!}
|
||||
class="{{ $disabled ? 'opacity-25 cursor-not-allowed' : 'cursor-pointer' }} font-medium border rounded transition duration-200 shadow-sm focus:ring focus:ring-opacity-50 text-sm py-2 px-4 border-transparent bg-danger-600 text-white hover:bg-danger-700 focus:ring-danger-200"
|
||||
>
|
||||
{{ __('tables::table.delete.button.label') }}
|
||||
</button>
|
||||
|
||||
@@ -49,11 +49,7 @@
|
||||
</th>
|
||||
@endforeach
|
||||
|
||||
@if ($table->recordButtonLabel)
|
||||
<th scope="col">
|
||||
<span class="sr-only">{{ __($table->recordButtonLabel) }}</span>
|
||||
</th>
|
||||
@endif
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -78,32 +74,17 @@
|
||||
</td>
|
||||
@endforeach
|
||||
|
||||
@if ($table->recordButtonLabel)
|
||||
<td class="px-6 py-4 text-right whitespace-nowrap">
|
||||
@if ($table->recordAction)
|
||||
<button
|
||||
wire:click="{{ $table->recordAction }}('{{ $record->getKey() }}')"
|
||||
type="button"
|
||||
class="font-medium transition-colors duration-200 text-primary-600 hover:underline hover:text-primary-700"
|
||||
>
|
||||
{{ __($table->recordButtonLabel) }}
|
||||
</button>
|
||||
@elseif ($table->recordUrl)
|
||||
<a
|
||||
href="{{ $table->getRecordUrl($record) }}"
|
||||
class="font-medium transition-colors duration-200 text-primary-600 hover:underline hover:text-primary-700"
|
||||
>
|
||||
{{ __($table->recordButtonLabel) }}
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
@endif
|
||||
<td class="px-6 py-4 text-right whitespace-nowrap">
|
||||
@foreach ($table->recordActions as $recordAction)
|
||||
{{ $recordAction->render($record) }}
|
||||
@endforeach
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td
|
||||
class="px-6 py-4 whitespace-nowrap"
|
||||
colspan="{{ count($table->getVisibleColumns()) + 1 + ($table->recordButtonLabel ? 1 : 0) }}"
|
||||
colspan="{{ count($table->getVisibleColumns()) + 2 }}"
|
||||
>
|
||||
<div class="flex items-center justify-center h-16">
|
||||
<p class="font-mono text-xs text-gray-500">
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
@if ($recordAction->action)
|
||||
<button
|
||||
wire:click="{{ $recordAction->action }}('{{ $record->getKey() }}')"
|
||||
type="button"
|
||||
class="font-medium transition-colors duration-200 text-primary-600 hover:underline hover:text-primary-700"
|
||||
>
|
||||
{{ __($recordAction->label) }}
|
||||
</button>
|
||||
@elseif ($recordAction->url)
|
||||
<a
|
||||
href="{{ $recordAction->getUrl($record) }}"
|
||||
class="font-medium transition-colors duration-200 text-primary-600 hover:underline hover:text-primary-700"
|
||||
@if ($recordAction->shouldOpenUrlInNewTab)
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@endif
|
||||
>
|
||||
{{ __($recordAction->label) }}
|
||||
</a>
|
||||
@else
|
||||
<span>{{ __($recordAction->label) }}</span>
|
||||
@endif
|
||||
@@ -174,6 +174,8 @@ class Column
|
||||
->replace(['-', '_', '.'], ' ')
|
||||
->ucfirst(),
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function only($contexts, $callback = null)
|
||||
@@ -253,7 +255,7 @@ class Column
|
||||
{
|
||||
if ($this->hidden) return;
|
||||
|
||||
$view = $this->view ?? 'tables::cells.'.Str::of(class_basename(static::class))->kebab();
|
||||
$view = $this->view ?? 'tables::cells.' . Str::of(class_basename(static::class))->kebab();
|
||||
|
||||
return view($view, array_merge($this->viewData, [
|
||||
'column' => $this,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Filament\Tables\Columns;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Text extends Column
|
||||
{
|
||||
@@ -85,4 +86,13 @@ class Text extends Column
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function limit($length = -1)
|
||||
{
|
||||
$this->formatUsing = function ($value) use ($length) {
|
||||
return Str::limit($value, $length);
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tables\RecordActions;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Traits\Tappable;
|
||||
|
||||
class Action
|
||||
{
|
||||
use Tappable;
|
||||
|
||||
public $name;
|
||||
|
||||
public $view;
|
||||
|
||||
public $viewData = [];
|
||||
|
||||
public $when;
|
||||
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name($name);
|
||||
|
||||
$this->when(fn ($record) => true);
|
||||
|
||||
$this->setUp();
|
||||
}
|
||||
|
||||
public static function make($name)
|
||||
{
|
||||
return new static($name);
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function name($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function view($view, $data = [])
|
||||
{
|
||||
$this->view = $view;
|
||||
|
||||
$this->viewData($data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function viewData($data = [])
|
||||
{
|
||||
$this->viewData = array_merge($this->viewData, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function when($callback)
|
||||
{
|
||||
$this->when = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render($record)
|
||||
{
|
||||
$when = $this->when;
|
||||
|
||||
if (! $when($record)) return;
|
||||
|
||||
$view = $this->view ?? 'tables::record-actions.' . Str::of(class_basename(static::class))->kebab();
|
||||
|
||||
return view($view, array_merge($this->viewData, [
|
||||
'record' => $record,
|
||||
'recordAction' => $this,
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tables\RecordActions\Concerns;
|
||||
|
||||
trait CanCallAction
|
||||
{
|
||||
public $action;
|
||||
|
||||
public function action($action)
|
||||
{
|
||||
$this->action = $action;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tables\RecordActions\Concerns;
|
||||
|
||||
trait CanOpenUrl
|
||||
{
|
||||
public $shouldOpenUrlInNewTab = false;
|
||||
|
||||
public $url;
|
||||
|
||||
public function getUrl($record)
|
||||
{
|
||||
if (is_callable($this->url)) {
|
||||
$callback = $this->url;
|
||||
|
||||
return $callback($record);
|
||||
}
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function openUrlInNewTab()
|
||||
{
|
||||
$this->shouldOpenUrlInNewTab = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function url($url, $shouldOpenInNewTab = false)
|
||||
{
|
||||
$this->url = $url;
|
||||
if ($shouldOpenInNewTab) $this->openUrlInNewTab();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tables\RecordActions;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Link extends Action
|
||||
{
|
||||
use Concerns\CanCallAction;
|
||||
use Concerns\CanOpenUrl;
|
||||
|
||||
public $label;
|
||||
|
||||
public function label($label)
|
||||
{
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function name($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
$this->label(
|
||||
(string) Str::of($this->name)
|
||||
->kebab()
|
||||
->replace(['-', '_', '.'], ' ')
|
||||
->ucfirst(),
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,7 @@ class Table
|
||||
|
||||
public $pagination = true;
|
||||
|
||||
public $recordAction;
|
||||
|
||||
public $recordButtonLabel = 'tables::table.record.button.label';
|
||||
|
||||
public $recordUrl;
|
||||
public $recordActions = [];
|
||||
|
||||
public $searchable = true;
|
||||
|
||||
@@ -93,17 +89,6 @@ class Table
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRecordUrl($record = null)
|
||||
{
|
||||
if (is_callable($this->recordUrl)) {
|
||||
$callback = $this->recordUrl;
|
||||
|
||||
return $callback($record);
|
||||
}
|
||||
|
||||
return $this->recordUrl;
|
||||
}
|
||||
|
||||
public function getVisibleColumns()
|
||||
{
|
||||
$columns = collect($this->columns)
|
||||
@@ -153,43 +138,9 @@ class Table
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function recordAction($action)
|
||||
public function recordActions($actions)
|
||||
{
|
||||
$this->recordAction = $action;
|
||||
|
||||
$this->columns = collect($this->columns)
|
||||
->map(function ($column) {
|
||||
if ($column->primary && ! $column->action) {
|
||||
$column->action($this->recordAction);
|
||||
}
|
||||
|
||||
return $column;
|
||||
})
|
||||
->toArray();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function recordButtonLabel($label)
|
||||
{
|
||||
$this->recordButtonLabel = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function recordUrl($url)
|
||||
{
|
||||
$this->recordUrl = $url;
|
||||
|
||||
$this->columns = collect($this->columns)
|
||||
->map(function ($column) {
|
||||
if ($column->primary && ! $column->url) {
|
||||
$column->url($this->recordUrl);
|
||||
}
|
||||
|
||||
return $column;
|
||||
})
|
||||
->toArray();
|
||||
$this->recordActions = $actions;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
+36
-36
@@ -1,41 +1,41 @@
|
||||
@layer base {
|
||||
:root {
|
||||
--f-primary-100: theme('colors.lightBlue.100');
|
||||
--f-primary-200: theme('colors.lightBlue.200');
|
||||
--f-primary-300: theme('colors.lightBlue.300');
|
||||
--f-primary-400: theme('colors.lightBlue.400');
|
||||
--f-primary-500: theme('colors.lightBlue.500');
|
||||
--f-primary-600: theme('colors.lightBlue.600');
|
||||
--f-primary-700: theme('colors.lightBlue.700');
|
||||
--f-primary-800: theme('colors.lightBlue.800');
|
||||
--f-primary-900: theme('colors.lightBlue.900');
|
||||
--f-success-100: theme('colors.emerald.100');
|
||||
--f-success-200: theme('colors.emerald.200');
|
||||
--f-success-300: theme('colors.emerald.300');
|
||||
--f-success-400: theme('colors.emerald.400');
|
||||
--f-success-500: theme('colors.emerald.500');
|
||||
--f-success-600: theme('colors.emerald.600');
|
||||
--f-success-700: theme('colors.emerald.700');
|
||||
--f-success-800: theme('colors.emerald.800');
|
||||
--f-success-900: theme('colors.emerald.900');
|
||||
--f-danger-100: theme('colors.rose.100');
|
||||
--f-danger-200: theme('colors.rose.200');
|
||||
--f-danger-300: theme('colors.rose.300');
|
||||
--f-danger-400: theme('colors.rose.400');
|
||||
--f-danger-500: theme('colors.rose.500');
|
||||
--f-danger-600: theme('colors.rose.600');
|
||||
--f-danger-700: theme('colors.rose.700');
|
||||
--f-danger-800: theme('colors.rose.800');
|
||||
--f-danger-900: theme('colors.rose.900');
|
||||
--f-gray-100: theme('colors.coolGray.100');
|
||||
--f-gray-200: theme('colors.coolGray.200');
|
||||
--f-gray-300: theme('colors.coolGray.300');
|
||||
--f-gray-400: theme('colors.coolGray.400');
|
||||
--f-gray-500: theme('colors.coolGray.500');
|
||||
--f-gray-600: theme('colors.coolGray.600');
|
||||
--f-gray-700: theme('colors.coolGray.700');
|
||||
--f-gray-800: theme('colors.coolGray.800');
|
||||
--f-gray-900: theme('colors.coolGray.900');
|
||||
--f-primary-100: theme('colors.defaultPrimary.100');
|
||||
--f-primary-200: theme('colors.defaultPrimary.200');
|
||||
--f-primary-300: theme('colors.defaultPrimary.300');
|
||||
--f-primary-400: theme('colors.defaultPrimary.400');
|
||||
--f-primary-500: theme('colors.defaultPrimary.500');
|
||||
--f-primary-600: theme('colors.defaultPrimary.600');
|
||||
--f-primary-700: theme('colors.defaultPrimary.700');
|
||||
--f-primary-800: theme('colors.defaultPrimary.800');
|
||||
--f-primary-900: theme('colors.defaultPrimary.900');
|
||||
--f-success-100: theme('colors.defaultSuccess.100');
|
||||
--f-success-200: theme('colors.defaultSuccess.200');
|
||||
--f-success-300: theme('colors.defaultSuccess.300');
|
||||
--f-success-400: theme('colors.defaultSuccess.400');
|
||||
--f-success-500: theme('colors.defaultSuccess.500');
|
||||
--f-success-600: theme('colors.defaultSuccess.600');
|
||||
--f-success-700: theme('colors.defaultSuccess.700');
|
||||
--f-success-800: theme('colors.defaultSuccess.800');
|
||||
--f-success-900: theme('colors.defaultSuccess.900');
|
||||
--f-danger-100: theme('colors.defaultDanger.100');
|
||||
--f-danger-200: theme('colors.defaultDanger.200');
|
||||
--f-danger-300: theme('colors.defaultDanger.300');
|
||||
--f-danger-400: theme('colors.defaultDanger.400');
|
||||
--f-danger-500: theme('colors.defaultDanger.500');
|
||||
--f-danger-600: theme('colors.defaultDanger.600');
|
||||
--f-danger-700: theme('colors.defaultDanger.700');
|
||||
--f-danger-800: theme('colors.defaultDanger.800');
|
||||
--f-danger-900: theme('colors.defaultDanger.900');
|
||||
--f-gray-100: theme('colors.defaultGray.100');
|
||||
--f-gray-200: theme('colors.defaultGray.200');
|
||||
--f-gray-300: theme('colors.defaultGray.300');
|
||||
--f-gray-400: theme('colors.defaultGray.400');
|
||||
--f-gray-500: theme('colors.defaultGray.500');
|
||||
--f-gray-600: theme('colors.defaultGray.600');
|
||||
--f-gray-700: theme('colors.defaultGray.700');
|
||||
--f-gray-800: theme('colors.defaultGray.800');
|
||||
--f-gray-900: theme('colors.defaultGray.900');
|
||||
--f-blue-100: theme('colors.defaultBlue.100');
|
||||
--f-blue-200: theme('colors.defaultBlue.200');
|
||||
--f-blue-300: theme('colors.defaultBlue.300');
|
||||
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Bearbeiten',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Edit',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Editar',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Modifier',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'submit' => [
|
||||
'label' => 'Masuk',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'form' => [
|
||||
|
||||
'email' => [
|
||||
'label' => 'Alamat email',
|
||||
],
|
||||
|
||||
'password' => [
|
||||
'hint' => 'Lupa kata sandi anda?',
|
||||
'label' => 'Kata sandi',
|
||||
],
|
||||
|
||||
'remember' => [
|
||||
'label' => 'Ingat saya',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
'failed' => 'Identitas tersebut tidak cocok dengan data kami.',
|
||||
'throttled' => 'Terlalu banyak upaya masuk. Silahkan coba lagi dalam :seconds detik.',
|
||||
],
|
||||
|
||||
'title' => 'Masuk ke akun anda',
|
||||
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'button' => [
|
||||
'label' => 'Keluar',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'submit' => [
|
||||
'label' => 'Kirim link reset sandi',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'form' => [
|
||||
|
||||
'email' => [
|
||||
'hint' => 'Kembali ke login',
|
||||
'label' => 'Alamat email',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
|
||||
'throttled' => 'Terlalu banyak upaya masuk. Silahkan coba lagi dalam :seconds detik.',
|
||||
|
||||
'passwords' => [
|
||||
'sent' => 'Kami sudah mengirimkan email yang berisi tautan untuk mereset sandi anda!',
|
||||
'throttled' => 'Harap tunggu sebelum mencoba lagi.',
|
||||
'user' => 'Kami tidak menemukan pengguna dengan alamat email tersebut.',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'title' => 'Reset kata sandi',
|
||||
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'submit' => [
|
||||
'label' => 'Reset kata sandi',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'form' => [
|
||||
|
||||
'email' => [
|
||||
'label' => 'Alamat email',
|
||||
],
|
||||
|
||||
'password' => [
|
||||
'label' => 'Kata sandi',
|
||||
],
|
||||
|
||||
'passwordConfirmation' => [
|
||||
'label' => 'Konfirmasi kata sandi',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
|
||||
'passwords' => [
|
||||
'throttled' => 'Harap tunggu sebelum mencoba lagi.',
|
||||
'token' => 'Token reset kata sandi ini tidak valid.',
|
||||
'user' => 'Kami tidak menemukan pengguna dengan alamat email tersebut.',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'title' => 'Reset kata sandi',
|
||||
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'title' => 'Beranda',
|
||||
|
||||
'widgets' => [
|
||||
|
||||
'account' => [
|
||||
|
||||
'heading' => 'Selamat datang, :name',
|
||||
|
||||
'links' => [
|
||||
|
||||
'account' => [
|
||||
'label' => 'Atur akun anda',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'filament' => [
|
||||
|
||||
'links' => [
|
||||
|
||||
'documentation' => [
|
||||
'label' => 'Baca dokumentasi',
|
||||
],
|
||||
|
||||
'repository' => [
|
||||
'label' => 'Buka repository',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'save' => [
|
||||
'label' => 'Simpan',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
'saved' => 'Tersimpan!',
|
||||
],
|
||||
|
||||
'title' => 'Akun',
|
||||
|
||||
];
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'dropdown' => [
|
||||
|
||||
'account' => [
|
||||
'label' => 'Edit akun',
|
||||
],
|
||||
|
||||
'users' => [
|
||||
'label' => 'Manajemen pengguna',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'create' => [
|
||||
'label' => 'Buat',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'delete' => [
|
||||
'label' => 'Hapus',
|
||||
],
|
||||
|
||||
'save' => [
|
||||
'label' => 'Simpan',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'modals' => [
|
||||
|
||||
'delete' => [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'cancel' => [
|
||||
'label' => 'Batalkan',
|
||||
],
|
||||
|
||||
'confirm' => [
|
||||
'label' => 'Konfirmasi',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'description' => 'Apakah anda yakin ingin menghapus data ini? Aksi ini tidak bisa dibatalkan.',
|
||||
|
||||
'heading' => 'Hapus data ini?',
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'messages' => [
|
||||
'saved' => 'Tersimpan!',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'create' => [
|
||||
'label' => 'Buat',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Edit',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'attach' => [
|
||||
'label' => 'Sambungkan yang sudah ada',
|
||||
],
|
||||
|
||||
'create' => [
|
||||
'label' => 'Baru',
|
||||
],
|
||||
|
||||
'detach' => [
|
||||
'label' => 'Putuskan yang terpilih'
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'modals' => [
|
||||
|
||||
'attach' => [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'cancel' => [
|
||||
'label' => 'Batalkan',
|
||||
],
|
||||
|
||||
'attach' => [
|
||||
'label' => 'Sambungkan',
|
||||
],
|
||||
|
||||
'attachAnother' => [
|
||||
'label' => 'Sambungkan ini lalu sambungkan yang lain',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'form' => [
|
||||
|
||||
'related' => [
|
||||
'placeholder' => 'Mulai mengetik untuk mencari...',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'heading' => 'Sambungkan yang sudah ada',
|
||||
|
||||
'messages' => [
|
||||
'attached' => 'Tersambung!',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'create' => [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'cancel' => [
|
||||
'label' => 'Batal',
|
||||
],
|
||||
|
||||
'create' => [
|
||||
'label' => 'Buat',
|
||||
],
|
||||
|
||||
'createAnother' => [
|
||||
'label' => 'Buat ini lalu buat yang baru',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'heading' => 'Buat',
|
||||
|
||||
'messages' => [
|
||||
'created' => 'Dibuat!',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'detach' => [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'cancel' => [
|
||||
'label' => 'Batalkan',
|
||||
],
|
||||
|
||||
'detach' => [
|
||||
'label' => 'Putus yang dipilih',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'description' => 'Apakah anda yakin ingin memutuskan data yang dipilih? Aksi ini tidak bisa dibatalkan.',
|
||||
|
||||
'heading' => 'Putuskan data yang dipilih? ',
|
||||
|
||||
'messages' => [
|
||||
'detached' => 'Terputuskan!',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'edit' => [
|
||||
|
||||
'buttons' => [
|
||||
|
||||
'cancel' => [
|
||||
'label' => 'Batalkan',
|
||||
],
|
||||
|
||||
'save' => [
|
||||
'label' => 'Simpan',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'heading' => 'Edit',
|
||||
|
||||
'messages' => [
|
||||
'saved' => 'Tersimpan!',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'form' => [
|
||||
|
||||
'avatar' => [
|
||||
'label' => 'Avatar',
|
||||
],
|
||||
|
||||
'email' => [
|
||||
'label' => 'Alamat email',
|
||||
],
|
||||
|
||||
'isAdmin' => [
|
||||
'label' => 'Admin Filament?',
|
||||
'helpMessage' => 'Admin Filament dapat mengakses semua area yang dimiliki filament dan mengatur pengguna lain',
|
||||
],
|
||||
|
||||
'isUser' => [
|
||||
'label' => 'Pengguna Filament?',
|
||||
],
|
||||
|
||||
'name' => [
|
||||
'label' => 'Nama',
|
||||
],
|
||||
|
||||
'password' => [
|
||||
|
||||
'fieldset' => [
|
||||
|
||||
'label' => [
|
||||
'create' => 'Password',
|
||||
'edit' => 'Buat password baru',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'fields' => [
|
||||
|
||||
'password' => [
|
||||
'label' => 'Password',
|
||||
],
|
||||
|
||||
'passwordConfirmation' => [
|
||||
'label' => 'Konfirmasi password',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'roles' => [
|
||||
'label' => 'Role',
|
||||
'placeholder' => 'Pilih role',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'columns' => [
|
||||
|
||||
'email' => [
|
||||
'label' => 'Alamat email',
|
||||
],
|
||||
|
||||
'name' => [
|
||||
'label' => 'Nama',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'filters' => [
|
||||
|
||||
'administrators' => [
|
||||
'label' => 'Administrator',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Modifica',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Bewerk',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -10,4 +10,16 @@ return [
|
||||
|
||||
],
|
||||
|
||||
'table' => [
|
||||
|
||||
'recordActions' => [
|
||||
|
||||
'edit' => [
|
||||
'label' => 'Editar',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
'path' => 'css/filament.css',
|
||||
]) }}" />
|
||||
|
||||
@foreach (\Filament\Filament::getStyles() as $style)
|
||||
<link rel="stylesheet" href="{{ $style }}">
|
||||
@foreach (\Filament\Filament::getStyles() as $path)
|
||||
<link rel="stylesheet" href="{{ $path }}" />
|
||||
@endforeach
|
||||
|
||||
@stack('filament-styles')
|
||||
@@ -37,8 +37,8 @@
|
||||
'path' => 'js/filament.js',
|
||||
]) }}"></script>
|
||||
|
||||
@foreach (\Filament\Filament::getScripts() as $script)
|
||||
<script src="{{ $script }}"></script>
|
||||
@foreach (\Filament\Filament::getScripts() as $path)
|
||||
<script src="{{ $path }}"></script>
|
||||
@endforeach
|
||||
|
||||
@stack('filament-scripts')
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
<div class="space-y-6">
|
||||
@foreach ($relations as $manager)
|
||||
<x-filament::card>
|
||||
@livewire(\Livewire\Livewire::getAlias($manager, $manager::getName()), ['owner' => $owner], key($loop->index))
|
||||
</x-filament::card>
|
||||
@livewire(\Livewire\Livewire::getAlias($manager, $manager::getName()), ['owner' => $owner], key($loop->index))
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@@ -1,124 +1,132 @@
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-medium leading-tight">
|
||||
{{ __(static::getTitle()) }}
|
||||
</h3>
|
||||
@if (\Filament\Filament::can('viewAny', $this->getModel()))
|
||||
<x-filament::card class="space-y-4">
|
||||
<h3 class="text-lg font-medium leading-tight">
|
||||
{{ __(static::getTitle()) }}
|
||||
</h3>
|
||||
|
||||
<div class="items-center justify-between space-y-4 lg:flex lg:space-y-0 lg:space-x-4">
|
||||
<div class="space-x-3 flex-shink-0">
|
||||
<x-filament::button wire:click="openCreate">
|
||||
{{ __(static::$createButtonLabel) }}
|
||||
</x-filament::button>
|
||||
<div class="items-center justify-between space-y-4 lg:flex lg:space-y-0 lg:space-x-4">
|
||||
<div class="space-x-3 flex-shink-0">
|
||||
@if ($this->canCreate())
|
||||
<x-filament::button wire:click="openCreate">
|
||||
{{ __(static::$createButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
|
||||
@if ($this->canAttach())
|
||||
<x-filament::button wire:click="openAttach">
|
||||
{{ __(static::$attachButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
@if ($this->canAttach())
|
||||
<x-filament::button wire:click="openAttach">
|
||||
{{ __(static::$attachButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
|
||||
@if ($this->canDetach())
|
||||
<x-filament::button
|
||||
wire:click="openDetach"
|
||||
color="danger"
|
||||
:disabled="count($selected) === 0"
|
||||
>
|
||||
{{ __(static::$detachButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
@if ($this->canDetachSelected())
|
||||
<x-filament::button
|
||||
wire:click="openDetach"
|
||||
color="danger"
|
||||
:disabled="count($selected) === 0"
|
||||
>
|
||||
{{ __(static::$detachButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
|
||||
<x-tables::delete-selected :selected="$selected" />
|
||||
@if ($this->canDelete())
|
||||
<x-tables::delete-selected :disabled="! $this->canDeleteSelected()" />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<x-tables::filter :table="$this->getTable()" />
|
||||
</div>
|
||||
|
||||
<x-tables::filter :table="$this->getTable()" />
|
||||
</div>
|
||||
<x-tables::table
|
||||
:records="$records"
|
||||
:selected="$selected"
|
||||
:sort-column="$sortColumn"
|
||||
:sort-direction="$sortDirection"
|
||||
:table="$this->getTable()"
|
||||
/>
|
||||
|
||||
<x-tables::table
|
||||
:records="$records"
|
||||
:selected="$selected"
|
||||
:sort-column="$sortColumn"
|
||||
:sort-direction="$sortDirection"
|
||||
:table="$this->getTable()"
|
||||
/>
|
||||
@if ($this->canCreate())
|
||||
<x-filament::modal
|
||||
class="w-full max-w-4xl"
|
||||
:name="static::class . 'RelationManagerCreateModal'"
|
||||
>
|
||||
<x-filament::card class="space-y-5">
|
||||
<x-filament::card-header :title="__(static::$createModalHeading)" />
|
||||
|
||||
<x-filament::modal
|
||||
class="w-full max-w-4xl"
|
||||
:name="static::class . 'RelationManagerCreateModal'"
|
||||
>
|
||||
<x-filament::card class="space-y-5">
|
||||
<x-filament::card-header :title="__(static::$createModalHeading)" />
|
||||
@livewire(\Livewire\Livewire::getAlias(Filament\Resources\RelationManager\CreateRecord::class), [
|
||||
'cancelButtonLabel' => __(static::$createModalCancelButtonLabel),
|
||||
'createAnotherButtonLabel' => __(static::$createModalCreateAnotherButtonLabel),
|
||||
'createButtonLabel' => __(static::$createModalCreateButtonLabel),
|
||||
'createdMessage' => __(static::$createModalCreatedMessage),
|
||||
'manager' => static::class,
|
||||
'owner' => $this->owner,
|
||||
])
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
@endif
|
||||
|
||||
@livewire(\Livewire\Livewire::getAlias(Filament\Resources\RelationManager\CreateRecord::class), [
|
||||
'cancelButtonLabel' => __(static::$createModalCancelButtonLabel),
|
||||
'createAnotherButtonLabel' => __(static::$createModalCreateAnotherButtonLabel),
|
||||
'createButtonLabel' => __(static::$createModalCreateButtonLabel),
|
||||
'createdMessage' => __(static::$createModalCreatedMessage),
|
||||
'manager' => static::class,
|
||||
'owner' => $this->owner,
|
||||
])
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
|
||||
<x-filament::modal
|
||||
class="w-full max-w-4xl"
|
||||
:name="static::class . 'RelationManagerEditModal'"
|
||||
>
|
||||
<x-filament::card class="space-y-5">
|
||||
<x-filament::card-header :title="__(static::$editModalHeading)" />
|
||||
|
||||
@livewire(\Livewire\Livewire::getAlias(Filament\Resources\RelationManager\EditRecord::class), [
|
||||
'cancelButtonLabel' => __(static::$editModalCancelButtonLabel),
|
||||
'manager' => static::class,
|
||||
'owner' => $this->owner,
|
||||
'saveButtonLabel' => __(static::$editModalSaveButtonLabel),
|
||||
'savedMessage' => __(static::$editModalSavedMessage),
|
||||
])
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
|
||||
@if ($this->canAttach())
|
||||
<x-filament::modal
|
||||
class="w-full max-w-lg"
|
||||
:name="static::class . 'RelationManagerAttachModal'"
|
||||
class="w-full max-w-4xl"
|
||||
:name="static::class . 'RelationManagerEditModal'"
|
||||
>
|
||||
<x-filament::card class="w-full space-y-5">
|
||||
<x-filament::card-header :title="__(static::$attachModalHeading)" />
|
||||
<x-filament::card class="space-y-5">
|
||||
<x-filament::card-header :title="__(static::$editModalHeading)" />
|
||||
|
||||
@livewire(\Livewire\Livewire::getAlias(Filament\Resources\RelationManager\AttachRecord::class), [
|
||||
'cancelButtonLabel' => __(static::$attachModalCancelButtonLabel),
|
||||
'attachAnotherButtonLabel' => __(static::$attachModalAttachAnotherButtonLabel),
|
||||
'attachButtonLabel' => __(static::$attachModalAttachButtonLabel),
|
||||
'attachedMessage' => __(static::$attachModalAttachedMessage),
|
||||
@livewire(\Livewire\Livewire::getAlias(Filament\Resources\RelationManager\EditRecord::class), [
|
||||
'cancelButtonLabel' => __(static::$editModalCancelButtonLabel),
|
||||
'manager' => static::class,
|
||||
'owner' => $this->owner,
|
||||
'saveButtonLabel' => __(static::$editModalSaveButtonLabel),
|
||||
'savedMessage' => __(static::$editModalSavedMessage),
|
||||
])
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
@endif
|
||||
|
||||
@if ($this->canDetach())
|
||||
<x-filament::modal
|
||||
:name="static::class . 'RelationManagerDetachModal'"
|
||||
>
|
||||
<x-filament::card class="space-y-5">
|
||||
<x-filament::card-header :title="__(static::$detachModalHeading)">
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ __(static::$detachModalDescription) }}
|
||||
</p>
|
||||
</x-filament::card-header>
|
||||
@if ($this->canAttach())
|
||||
<x-filament::modal
|
||||
class="w-full max-w-lg"
|
||||
:name="static::class . 'RelationManagerAttachModal'"
|
||||
>
|
||||
<x-filament::card class="w-full space-y-5">
|
||||
<x-filament::card-header :title="__(static::$attachModalHeading)" />
|
||||
|
||||
<div class="space-y-3 sm:space-y-0 sm:space-x-3 sm:flex sm:justify-end">
|
||||
<x-filament::button x-on:click="$dispatch('close', '{{ (string) Str::of(get_class($this))->replace('\\', '\\\\') }}RelationManagerDetachModal')">
|
||||
{{ __(static::$detachModalCancelButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@livewire(\Livewire\Livewire::getAlias(Filament\Resources\RelationManager\AttachRecord::class), [
|
||||
'cancelButtonLabel' => __(static::$attachModalCancelButtonLabel),
|
||||
'attachAnotherButtonLabel' => __(static::$attachModalAttachAnotherButtonLabel),
|
||||
'attachButtonLabel' => __(static::$attachModalAttachButtonLabel),
|
||||
'attachedMessage' => __(static::$attachModalAttachedMessage),
|
||||
'manager' => static::class,
|
||||
'owner' => $this->owner,
|
||||
])
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
@endif
|
||||
|
||||
<x-filament::button
|
||||
type="button"
|
||||
color="danger"
|
||||
wire:click="detachSelected"
|
||||
>
|
||||
{{ __(static::$detachModalDetachButtonLabel) }}
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
@endif
|
||||
</div>
|
||||
@if ($this->canDetachSelected())
|
||||
<x-filament::modal
|
||||
:name="static::class . 'RelationManagerDetachModal'"
|
||||
>
|
||||
<x-filament::card class="space-y-5">
|
||||
<x-filament::card-header :title="__(static::$detachModalHeading)">
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ __(static::$detachModalDescription) }}
|
||||
</p>
|
||||
</x-filament::card-header>
|
||||
|
||||
<div class="space-y-3 sm:space-y-0 sm:space-x-3 sm:flex sm:justify-end">
|
||||
<x-filament::button x-on:click="$dispatch('close', '{{ (string) Str::of(get_class($this))->replace('\\', '\\\\') }}RelationManagerDetachModal')">
|
||||
{{ __(static::$detachModalCancelButtonLabel) }}
|
||||
</x-filament::button>
|
||||
|
||||
<x-filament::button
|
||||
type="button"
|
||||
color="danger"
|
||||
wire:click="detachSelected"
|
||||
>
|
||||
{{ __(static::$detachModalDetachButtonLabel) }}
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
@endif
|
||||
</x-filament::card>
|
||||
@endif
|
||||
|
||||
@@ -4,39 +4,41 @@
|
||||
:title="$title"
|
||||
>
|
||||
<x-slot name="actions">
|
||||
<x-filament::modal>
|
||||
<x-slot name="trigger">
|
||||
<x-filament::button
|
||||
x-on:click="open = true"
|
||||
color="danger"
|
||||
>
|
||||
{{ __(static::$deleteButtonLabel) }}
|
||||
</x-filament::button>
|
||||
</x-slot>
|
||||
|
||||
<x-filament::card class="space-y-5 max-w-2xl">
|
||||
<x-filament::card-header :title="__(static::$deleteModalHeading)">
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ __(static::$deleteModalDescription) }}
|
||||
</p>
|
||||
</x-filament::card-header>
|
||||
|
||||
<div class="space-y-3 sm:space-y-0 sm:flex sm:space-x-3 sm:justify-end">
|
||||
@if ($this->canDelete())
|
||||
<x-filament::modal>
|
||||
<x-slot name="trigger">
|
||||
<x-filament::button
|
||||
x-on:click="open = false"
|
||||
>
|
||||
{{ __(static::$deleteModalCancelButtonLabel) }}
|
||||
</x-filament::button>
|
||||
|
||||
<x-filament::button
|
||||
wire:click="delete"
|
||||
x-on:click="open = true"
|
||||
color="danger"
|
||||
>
|
||||
{{ __(static::$deleteModalConfirmButtonLabel) }}
|
||||
{{ __(static::$deleteButtonLabel) }}
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
</x-slot>
|
||||
|
||||
<x-filament::card class="space-y-5 max-w-2xl">
|
||||
<x-filament::card-header :title="__(static::$deleteModalHeading)">
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ __(static::$deleteModalDescription) }}
|
||||
</p>
|
||||
</x-filament::card-header>
|
||||
|
||||
<div class="space-y-3 sm:space-y-0 sm:flex sm:space-x-3 sm:justify-end">
|
||||
<x-filament::button
|
||||
x-on:click="open = false"
|
||||
>
|
||||
{{ __(static::$deleteModalCancelButtonLabel) }}
|
||||
</x-filament::button>
|
||||
|
||||
<x-filament::button
|
||||
wire:click="delete"
|
||||
color="danger"
|
||||
>
|
||||
{{ __(static::$deleteModalConfirmButtonLabel) }}
|
||||
</x-filament::button>
|
||||
</div>
|
||||
</x-filament::card>
|
||||
</x-filament::modal>
|
||||
@endif
|
||||
</x-slot>
|
||||
</x-filament::app-header>
|
||||
|
||||
|
||||
@@ -1,22 +1,38 @@
|
||||
<div>
|
||||
<x-filament::app-header :title="$title">
|
||||
<x-slot name="actions">
|
||||
<x-filament::button
|
||||
color="primary"
|
||||
:href="static::getResource()::generateUrl($createRoute)"
|
||||
>
|
||||
{{ __(static::$createButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@if ($this->canCreate())
|
||||
<x-filament::button
|
||||
color="primary"
|
||||
:href="static::getResource()::generateUrl($createRoute)"
|
||||
>
|
||||
{{ __(static::$createButtonLabel) }}
|
||||
</x-filament::button>
|
||||
@endif
|
||||
</x-slot>
|
||||
</x-filament::app-header>
|
||||
|
||||
<x-filament::app-content>
|
||||
<x-tables::container
|
||||
<x-filament::app-content class="space-y-4">
|
||||
<div class="items-center justify-between space-y-4 sm:flex sm:space-y-0">
|
||||
<div>
|
||||
@if ($this->canDelete())
|
||||
<x-tables::delete-selected :disabled="! $this->canDeleteSelected()" />
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<x-tables::filter :table="$this->getTable()" />
|
||||
</div>
|
||||
|
||||
<x-tables::table
|
||||
:records="$records"
|
||||
:selected="$selected"
|
||||
:sort-column="$sortColumn"
|
||||
:sort-direction="$sortDirection"
|
||||
:table="$this->getTable()"
|
||||
/>
|
||||
|
||||
@if ($this->getTable()->hasPagination())
|
||||
<x-tables::pagination.paginator :paginator="$records" />
|
||||
@endif
|
||||
</x-filament::app-content>
|
||||
</div>
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Filament;
|
||||
|
||||
class AuthorizationManager
|
||||
{
|
||||
public $authorizations = [];
|
||||
|
||||
public $mode = 'deny';
|
||||
|
||||
public $target;
|
||||
|
||||
public function __construct($target)
|
||||
{
|
||||
$this->target = $target;
|
||||
|
||||
$this->authorize($this->target::authorization());
|
||||
}
|
||||
|
||||
public function authorize($authorizations)
|
||||
{
|
||||
if (! $authorizations) return;
|
||||
|
||||
if (! is_array($authorizations)) {
|
||||
$authorizations = [$authorizations];
|
||||
}
|
||||
|
||||
if (! count($this->authorizations)) {
|
||||
$this->mode = $authorizations[0]->mode;
|
||||
}
|
||||
|
||||
$authorizations = array_filter(
|
||||
$authorizations,
|
||||
fn ($authorization) => $authorization->mode === $this->mode,
|
||||
);
|
||||
|
||||
$this->authorizations = array_merge($this->authorizations, $authorizations);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function can($action = null)
|
||||
{
|
||||
$user = Filament::auth()->user();
|
||||
|
||||
if (
|
||||
! count($this->authorizations) ||
|
||||
$user->isFilamentAdmin()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->mode === 'allow') {
|
||||
foreach ($this->authorizations as $authorization) {
|
||||
if ($user->hasFilamentRole($authorization->role)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->mode === 'deny') {
|
||||
foreach ($this->authorizations as $authorization) {
|
||||
if ($user->hasFilamentRole($authorization->role)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Filament\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class MakeThemeCommand extends Command
|
||||
{
|
||||
@@ -14,7 +15,10 @@ class MakeThemeCommand extends Command
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$path = resource_path("css/filament/{$this->argument('name')}.css");
|
||||
$theme = (string) Str::of($this->argument('name'))
|
||||
->trim(' ');
|
||||
|
||||
$path = resource_path("css/filament/{$theme}.css");
|
||||
|
||||
if ($this->checkForCollision([
|
||||
$path,
|
||||
@@ -22,6 +26,6 @@ class MakeThemeCommand extends Command
|
||||
|
||||
$this->copyStubToApp('Theme', $path);
|
||||
|
||||
$this->info("Successfully created {$this->argument('name')} theme!");
|
||||
$this->info("Successfully created {$theme} theme!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* @method static StatefulGuard auth()
|
||||
* @method static bool can(string $action, object|string $target)
|
||||
* @method static array getAuthorizations()
|
||||
* @method static array getPages()
|
||||
* @method static array getResources()
|
||||
* @method static array getRoles()
|
||||
@@ -16,6 +18,7 @@ use Illuminate\Support\Facades\Facade;
|
||||
* @method static array getStyles()
|
||||
* @method static array getWidgets()
|
||||
* @method static void provideToScript(array $variables)
|
||||
* @method static void registerAuthorizations(string $target, array $authorizations = [])
|
||||
* @method static void registerPage(string $page)
|
||||
* @method static void registerResource(string $resource)
|
||||
* @method static void registerRole(string $role)
|
||||
|
||||
+79
-6
@@ -7,9 +7,12 @@ use Filament\Events\ServingFilament;
|
||||
use Filament\Resources\UserResource;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class FilamentManager
|
||||
{
|
||||
public $authorizations = [];
|
||||
|
||||
public $pages = [];
|
||||
|
||||
public $resources = [];
|
||||
@@ -29,6 +32,64 @@ class FilamentManager
|
||||
return Auth::guard(config('filament.auth.guard', 'filament'));
|
||||
}
|
||||
|
||||
public function can($action, $target)
|
||||
{
|
||||
$user = $this->auth()->user();
|
||||
|
||||
if ($user->isFilamentAdmin()) return true;
|
||||
|
||||
$targetClass = is_object($target) ? get_class($target) : $target;
|
||||
|
||||
if (count($this->authorizations[$targetClass] ?? [])) {
|
||||
$mode = $this->authorizations[$targetClass][0]->mode;
|
||||
|
||||
$fallback = [
|
||||
'allow' => false,
|
||||
'deny' => true,
|
||||
][$mode];
|
||||
|
||||
foreach ($this->authorizations[$targetClass] as $authorization) {
|
||||
if ($mode !== $authorization->mode) continue;
|
||||
|
||||
if (! $user->hasFilamentRole($authorization->role)) continue;
|
||||
|
||||
if (in_array($action, $authorization->exceptActions)) continue;
|
||||
|
||||
if (in_array($action, $authorization->onlyActions)) {
|
||||
if ($mode === 'allow') return true;
|
||||
|
||||
if ($mode === 'deny') {
|
||||
$fallback = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($authorization->onlyActions)) continue;
|
||||
|
||||
return [
|
||||
'allow' => true,
|
||||
'deny' => false,
|
||||
][$mode];
|
||||
}
|
||||
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$policy = Gate::getPolicyFor($targetClass);
|
||||
|
||||
if ($policy === null || ! method_exists($policy, $action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Gate::check($action, $target);
|
||||
}
|
||||
|
||||
public function getAuthorizations()
|
||||
{
|
||||
return $this->authorizations;
|
||||
}
|
||||
|
||||
public function getPages()
|
||||
{
|
||||
return $this->pages;
|
||||
@@ -72,34 +133,46 @@ class FilamentManager
|
||||
$this->scriptData = array_merge($this->scriptData, $variables);
|
||||
}
|
||||
|
||||
public function registerAuthorizations($target, $authorizations = [])
|
||||
{
|
||||
$this->authorizations[$target] = array_merge(
|
||||
$this->authorizations[$target] ?? [],
|
||||
$authorizations,
|
||||
);
|
||||
}
|
||||
|
||||
public function registerPage($page)
|
||||
{
|
||||
$this->pages = array_merge($this->pages, [$page]);
|
||||
$this->pages[] = $page;
|
||||
|
||||
$this->registerAuthorizations($page, $page::authorization());
|
||||
}
|
||||
|
||||
public function registerResource($resource)
|
||||
{
|
||||
$this->resources = array_merge($this->resources, [$resource]);
|
||||
$this->resources[] = $resource;
|
||||
|
||||
$this->registerAuthorizations($resource::getModel(), $resource::authorization());
|
||||
}
|
||||
|
||||
public function registerRole($role)
|
||||
{
|
||||
$this->roles = array_merge($this->roles, [$role]);
|
||||
$this->roles[] = $role;
|
||||
}
|
||||
|
||||
public function registerScript($name, $script)
|
||||
public function registerScript($name, $path)
|
||||
{
|
||||
$this->scripts[$name] = $script;
|
||||
}
|
||||
|
||||
public function registerStyle($name, $style)
|
||||
public function registerStyle($name, $path)
|
||||
{
|
||||
$this->styles[$name] = $style;
|
||||
}
|
||||
|
||||
public function registerWidget($widget)
|
||||
{
|
||||
$this->widgets = array_merge($this->widgets, [$widget]);
|
||||
$this->widgets[] = $widget;
|
||||
}
|
||||
|
||||
public function serving($callback)
|
||||
|
||||
+10
-15
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Filament\Pages;
|
||||
|
||||
use Filament\AuthorizationManager;
|
||||
use Filament\Filament;
|
||||
use Filament\NavigationItem;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -22,21 +22,18 @@ class Page extends Component
|
||||
|
||||
public static $view;
|
||||
|
||||
public function __invoke(Container $container, \Illuminate\Routing\Route $route)
|
||||
{
|
||||
abort_unless($this->isAuthorized(), 403);
|
||||
|
||||
return parent::__invoke($container, $route);
|
||||
}
|
||||
|
||||
public static function authorization()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function authorizationManager()
|
||||
{
|
||||
return new AuthorizationManager(static::class);
|
||||
}
|
||||
|
||||
public static function can($action = null)
|
||||
{
|
||||
return static::authorizationManager()->can($action);
|
||||
}
|
||||
|
||||
public static function generateUrl($parameters = [], $absolute = true)
|
||||
{
|
||||
return route('filament.pages.' . static::route()->name, $parameters, $absolute);
|
||||
@@ -104,11 +101,9 @@ class Page extends Component
|
||||
return Route::make(static::getSlug(), static::getSlug());
|
||||
}
|
||||
|
||||
public function __invoke(Container $container, \Illuminate\Routing\Route $route)
|
||||
public function isAuthorized()
|
||||
{
|
||||
abort_unless(static::can(), 403);
|
||||
|
||||
return parent::__invoke($container, $route);
|
||||
return Filament::can('view', static::class);
|
||||
}
|
||||
|
||||
public function notify($message)
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace Filament\Resources\Pages;
|
||||
|
||||
use Filament\Filament;
|
||||
use Filament\Forms\HasForm;
|
||||
use Filament\Resources\Forms\Form;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class CreateRecord extends Page
|
||||
{
|
||||
@@ -57,6 +59,11 @@ class CreateRecord extends Page
|
||||
->submitMethod('create');
|
||||
}
|
||||
|
||||
public function isAuthorized()
|
||||
{
|
||||
return Filament::can('create', static::getModel());
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->record = [];
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Filament\Resources\Pages;
|
||||
|
||||
use Filament\Filament;
|
||||
use Filament\Forms\HasForm;
|
||||
use Filament\Resources\Forms\Form;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -37,8 +38,15 @@ class EditRecord extends Page
|
||||
];
|
||||
}
|
||||
|
||||
public function canDelete()
|
||||
{
|
||||
return Filament::can('delete', $this->record);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$this->authorize('delete');
|
||||
|
||||
$this->callHook('beforeDelete');
|
||||
|
||||
$this->record->delete();
|
||||
@@ -57,6 +65,11 @@ class EditRecord extends Page
|
||||
->submitMethod('save');
|
||||
}
|
||||
|
||||
public function isAuthorized()
|
||||
{
|
||||
return Filament::can('update', $this->record);
|
||||
}
|
||||
|
||||
public function mount($record)
|
||||
{
|
||||
$this->record = static::getModel()::findOrFail($record);
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Filament\Resources\Pages;
|
||||
|
||||
use Filament\Filament;
|
||||
use Filament\Resources\Tables\Table;
|
||||
use Filament\Resources\Tables\RecordActions;
|
||||
use Filament\Tables\HasTable;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -12,6 +14,8 @@ class ListRecords extends Page
|
||||
|
||||
public static $createButtonLabel = 'filament::resources/pages/list-records.buttons.create.label';
|
||||
|
||||
public static $editRecordActionLabel = 'filament::resources/pages/list-records.table.recordActions.edit.label';
|
||||
|
||||
public static $view = 'filament::resources.pages.list-records';
|
||||
|
||||
public $filterable = true;
|
||||
@@ -37,17 +41,60 @@ class ListRecords extends Page
|
||||
->title();
|
||||
}
|
||||
|
||||
public function canCreate()
|
||||
{
|
||||
return Filament::can('create', static::getModel());
|
||||
}
|
||||
|
||||
public function canDelete()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canDeleteSelected()
|
||||
{
|
||||
return static::getModel()::find($this->selected)
|
||||
->contains(function ($record) {
|
||||
return Filament::can('delete', $record);
|
||||
});
|
||||
}
|
||||
|
||||
public function deleteSelected()
|
||||
{
|
||||
$this->authorize('delete');
|
||||
|
||||
static::getModel()::destroy(
|
||||
static::getModel()::find($this->selected)
|
||||
->filter(function ($record) {
|
||||
return Filament::can('delete', $record);
|
||||
})
|
||||
->toArray(),
|
||||
);
|
||||
|
||||
$this->selected = [];
|
||||
}
|
||||
|
||||
public function getTable()
|
||||
{
|
||||
return static::getResource()::table(Table::make())
|
||||
->context(static::class)
|
||||
->filterable($this->filterable)
|
||||
->pagination($this->pagination)
|
||||
->recordUrl(fn ($record) => $this->getResource()::generateUrl($this->recordRoute, ['record' => $record]))
|
||||
->recordActions([
|
||||
RecordActions\Link::make('edit')
|
||||
->label(static::$editRecordActionLabel)
|
||||
->url(fn ($record) => $this->getResource()::generateUrl($this->recordRoute, ['record' => $record]))
|
||||
->when(fn ($record) => Filament::can('update', $record)),
|
||||
])
|
||||
->searchable($this->searchable)
|
||||
->sortable($this->sortable);
|
||||
}
|
||||
|
||||
public function isAuthorized()
|
||||
{
|
||||
return Filament::can('viewAny', static::getModel());
|
||||
}
|
||||
|
||||
protected function viewData()
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -3,16 +3,12 @@
|
||||
namespace Filament\Resources\Pages;
|
||||
|
||||
use Filament\Resources\Route;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Page extends \Filament\Pages\Page
|
||||
{
|
||||
public static $resource;
|
||||
|
||||
public static function authorizationManager()
|
||||
{
|
||||
return static::getResource()::authorizationManager();
|
||||
}
|
||||
|
||||
public static function getResource()
|
||||
{
|
||||
return static::$resource;
|
||||
@@ -33,6 +29,15 @@ class Page extends \Filament\Pages\Page
|
||||
return static::getModel()::query();
|
||||
}
|
||||
|
||||
protected function authorize($action)
|
||||
{
|
||||
$method = (string) Str::of($action)->ucfirst()->prepend('can');
|
||||
|
||||
if (! method_exists($this, $method)) return true;
|
||||
|
||||
abort_unless($this->{$method}() ?? true, 403);
|
||||
}
|
||||
|
||||
protected function callHook($hook)
|
||||
{
|
||||
if (! method_exists($this, $hook)) return;
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Filament\Resources;
|
||||
|
||||
use Filament\Filament;
|
||||
use Filament\Resources\Tables\Table;
|
||||
use Filament\Resources\Tables\RecordActions;
|
||||
use Filament\Tables\HasTable;
|
||||
use Illuminate\Database\Eloquent\Relations;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -56,6 +58,8 @@ class RelationManager extends Component
|
||||
|
||||
public static $editModalSavedMessage = 'filament::resources/relation-manager.modals.edit.messages.saved';
|
||||
|
||||
public static $editRecordActionLabel = 'filament::resources/pages/list-records.table.recordActions.edit.label';
|
||||
|
||||
public static $relationship;
|
||||
|
||||
public $filterable = true;
|
||||
@@ -102,7 +106,25 @@ class RelationManager extends Component
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canDetach()
|
||||
public function canCreate()
|
||||
{
|
||||
return Filament::can('create', $this->getModel());
|
||||
}
|
||||
|
||||
public function canDelete()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canDeleteSelected()
|
||||
{
|
||||
return $this->getModel()::find($this->selected)
|
||||
->contains(function ($record) {
|
||||
return Filament::can('delete', $record);
|
||||
});
|
||||
}
|
||||
|
||||
public function canDetachSelected()
|
||||
{
|
||||
if (
|
||||
$this->isType(Relations\HasMany::class) ||
|
||||
@@ -112,6 +134,21 @@ class RelationManager extends Component
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteSelected()
|
||||
{
|
||||
abort_unless($this->canDelete(), 403);
|
||||
|
||||
$this->getModel()::destroy(
|
||||
$this->getModel()::find($this->selected)
|
||||
->filter(function ($record) {
|
||||
return Filament::can('delete', $record);
|
||||
})
|
||||
->toArray(),
|
||||
);
|
||||
|
||||
$this->selected = [];
|
||||
}
|
||||
|
||||
public function detachSelected()
|
||||
{
|
||||
$relationship = $this->owner->{$this->getRelationship()}();
|
||||
@@ -129,7 +166,12 @@ class RelationManager extends Component
|
||||
return static::table(Table::make())
|
||||
->filterable($this->filterable)
|
||||
->pagination(false)
|
||||
->recordAction('openEdit')
|
||||
->recordActions([
|
||||
RecordActions\Link::make('edit')
|
||||
->label(static::$editRecordActionLabel)
|
||||
->action('openEdit')
|
||||
->when(fn ($record) => Filament::can('update', $record)),
|
||||
])
|
||||
->searchable($this->searchable)
|
||||
->sortable($this->sortable);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Filament\Resources\RelationManager;
|
||||
|
||||
use Filament\Filament;
|
||||
use Filament\Forms\HasForm;
|
||||
use Filament\Resources\Forms\Form;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -60,6 +61,8 @@ class EditRecord extends Component
|
||||
|
||||
public function save()
|
||||
{
|
||||
abort_unless(Filament::can('update', $this->record), 403);
|
||||
|
||||
$this->validateTemporaryUploadedFiles();
|
||||
|
||||
$this->storeTemporaryUploadedFiles();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Filament\Resources;
|
||||
|
||||
use Filament\AuthorizationManager;
|
||||
use Filament\NavigationItem;
|
||||
use Filament\Resources\Forms\Form;
|
||||
use Filament\Resources\Tables\Table;
|
||||
@@ -29,11 +28,6 @@ class Resource
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function authorizationManager()
|
||||
{
|
||||
return new AuthorizationManager(static::class);
|
||||
}
|
||||
|
||||
public static function form(Form $form)
|
||||
{
|
||||
return $form;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Resources\Tables\RecordActions;
|
||||
|
||||
class Link extends \Filament\Tables\RecordActions\Link
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -12,9 +12,9 @@ class Authorization
|
||||
|
||||
public $role;
|
||||
|
||||
public function __construct($role, $mode = 'deny')
|
||||
public function __construct($role, $mode)
|
||||
{
|
||||
$this->mode = in_array($mode, ['allow', 'deny']) ? $mode : 'deny';
|
||||
$this->mode = $mode;
|
||||
$this->role = $role;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Filament\View\Components;
|
||||
|
||||
use Filament\Filament;
|
||||
use Filament\NavigationItem;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class Nav extends Component
|
||||
@@ -22,13 +23,13 @@ class Nav extends Component
|
||||
);
|
||||
|
||||
foreach (Filament::getResources() as $resource) {
|
||||
if ($resource::authorizationManager()->can()) {
|
||||
if (Filament::can('viewAny', $resource::getModel())) {
|
||||
$this->items->push(...$resource::navigationItems());
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Filament::getPages() as $page) {
|
||||
if ($page::authorizationManager()->can()) {
|
||||
if (Filament::can('view', $page)) {
|
||||
$this->items->push(...$page::navigationItems());
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -77,12 +77,12 @@ module.exports = {
|
||||
900: 'var(--f-blue-900)',
|
||||
},
|
||||
white: 'var(--f-white)',
|
||||
lightBlue: colors.lightBlue,
|
||||
emerald: colors.emerald,
|
||||
rose: colors.rose,
|
||||
coolGray: colors.coolGray,
|
||||
defaultWhite: colors.white,
|
||||
defaultBlue: colors.blue
|
||||
defaultPrimary: colors.lightBlue,
|
||||
defaultSuccess: colors.emerald,
|
||||
defaultDanger: colors.rose,
|
||||
defaultGray: colors.coolGray,
|
||||
defaultBlue: colors.blue,
|
||||
defaultWhite: colors.white
|
||||
},
|
||||
keyframes: {
|
||||
shake: {
|
||||
|
||||
Reference in New Issue
Block a user