Masters and Transaction changes

This commit is contained in:
dhanabalan
2025-03-24 17:23:01 +05:30
parent 04ee0cadd5
commit c631f1f2c0
123 changed files with 6935 additions and 32 deletions

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Filament\Exports;
use App\Models\Item;
use Filament\Actions\Exports\ExportColumn;
use Filament\Actions\Exports\Exporter;
use Filament\Actions\Exports\Models\Export;
class ItemExporter extends Exporter
{
protected static ?string $model = Item::class;
public static function getColumns(): array
{
return [
ExportColumn::make('id')
->label('ID'),
ExportColumn::make('code'),
ExportColumn::make('description'),
ExportColumn::make('hourly_quantity'),
ExportColumn::make('created_at'),
ExportColumn::make('updated_at'),
ExportColumn::make('deleted_at'),
];
}
public static function getCompletedNotificationBody(Export $export): string
{
$body = 'Your item export has completed and '.number_format($export->successful_rows).' '.str('row')->plural($export->successful_rows).' exported.';
if ($failedRowsCount = $export->getFailedRowsCount()) {
$body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to export.';
}
return $body;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Filament\Imports;
use App\Models\Item;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
class ItemImporter extends Importer
{
protected static ?string $model = Item::class;
public static function getColumns(): array
{
return [
ImportColumn::make('code')
->requiredMapping()
->exampleHeader('Item Code')
->label('Item Code')
->rules(['required']),
ImportColumn::make('description')
->requiredMapping()
->exampleHeader('Description')
->label('Description')
->rules(['required']),
ImportColumn::make('hourly_quantity')
->requiredMapping()
->exampleHeader('Hourly Quantity')
->label('Hourly Quantity')
->numeric()
->rules(['required', 'integer']),
];
}
public function resolveRecord(): ?Item
{
// return Item::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
return new Item;
}
public static function getCompletedNotificationBody(Import $import): string
{
$body = 'Your item import has completed and '.number_format($import->successful_rows).' '.str('row')->plural($import->successful_rows).' imported.';
if ($failedRowsCount = $import->getFailedRowsCount()) {
$body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to import.';
}
return $body;
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace App\Filament\Imports;
use App\Models\ProductionQuantity;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
class ProductionQuantityImporter extends Importer
{
protected static ?string $model = ProductionQuantity::class;
public static function getColumns(): array
{
return [
ImportColumn::make('created_at')
->requiredMapping()
->exampleHeader('Created DateTime')
->label('Created DateTime')
->rules(['required']),
ImportColumn::make('plan_quantity')
->requiredMapping()
->exampleHeader('Plan Quantity')
->label('Plan Quantity')
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('hourly_quantity')
->requiredMapping()
->exampleHeader('Hourly Quantity')
->label('Hourly Quantity')
->numeric()
->rules(['required', 'integer']),
ImportColumn::make('item_code')
->requiredMapping()
->exampleHeader('Item Code')
->label('Item Code')
->rules(['required']),
ImportColumn::make('serial_number')
->requiredMapping()
->exampleHeader('Serial Number')
->label('Serial Number')
->rules(['required']),
ImportColumn::make('line')
->requiredMapping()
->exampleHeader('Line Name')
->label('Line Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('shift')
->requiredMapping()
->exampleHeader('Shift Name')
->label('Shift Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('block')
->requiredMapping()
->exampleHeader('Block Name')
->label('Block Name')
->relationship(resolveUsing:'name')
->rules(['required']),
ImportColumn::make('plant')
->requiredMapping()
->exampleHeader('Plant Name')
->label('Plant Name')
->relationship(resolveUsing:'name')
->rules(['required']),
];
}
public function resolveRecord(): ?ProductionQuantity
{
// return ProductionQuantity::firstOrNew([
// // Update existing records, matching them by `$this->data['column_name']`
// 'email' => $this->data['email'],
// ]);
return new ProductionQuantity();
}
public static function getCompletedNotificationBody(Import $import): string
{
$body = 'Your production quantity import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.';
if ($failedRowsCount = $import->getFailedRowsCount()) {
$body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.';
}
return $body;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
use Filament\Tables\Filters\SelectFilter;
class Dashboard extends \Filament\Pages\Dashboard
{
use HasFiltersForm;
public function filtersForm(Form $form): Form
{
return $form->schema([
Select::make('Plant')
->options(\DB::table('plants')->pluck('name', 'name')) // Fetch plant names
->label('Select Plant'),
Select::make('Line')
->options(\DB::table('lines')->pluck('name', 'name')) // Fetch line names
->label('Select Line'),
]);
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\BlockResource\Pages;
use App\Models\Block;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class BlockResource extends Resource
{
protected static ?string $model = Block::class;
protected static ?string $navigationIcon = 'codeat3/blade-clarity-icons';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->unique(ignoreRecord: true),
// ->columnSpanFull(),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListBlocks::route('/'),
'create' => Pages\CreateBlock::route('/create'),
'view' => Pages\ViewBlock::route('/{record}'),
'edit' => Pages\EditBlock::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateBlock extends CreateRecord
{
protected static string $resource = BlockResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditBlock extends EditRecord
{
protected static string $resource = BlockResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListBlocks extends ListRecords
{
protected static string $resource = BlockResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\BlockResource\Pages;
use App\Filament\Resources\BlockResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewBlock extends ViewRecord
{
protected static string $resource = BlockResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Filament\Resources\BlockResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class BlocksRelationManager extends RelationManager
{
protected static string $relationship = 'blocks';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('name')
->columns([
Tables\Columns\TextColumn::make('name'),
// Tables\Columns\TextColumn::make('plants.name'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -17,7 +17,9 @@ class CompanyResource extends Resource
{ {
protected static ?string $model = Company::class; protected static ?string $model = Company::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; protected static ?string $navigationIcon = 'heroicon-s-home-modern';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form public static function form(Form $form): Form
{ {
@@ -25,6 +27,7 @@ class CompanyResource extends Resource
->schema([ ->schema([
Forms\Components\TextInput::make('name') Forms\Components\TextInput::make('name')
->required() ->required()
->unique()
->columnSpanFull(), ->columnSpanFull(),
]); ]);
} }
@@ -37,7 +40,6 @@ class CompanyResource extends Resource
->label('ID') ->label('ID')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('name') Tables\Columns\TextColumn::make('name')
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('created_at') Tables\Columns\TextColumn::make('created_at')
@@ -45,10 +47,12 @@ class CompanyResource extends Resource
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('updated_at') Tables\Columns\TextColumn::make('updated_at')
->dateTime() ->dateTime()
->sortable(), ->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at') Tables\Columns\TextColumn::make('deleted_at')
->dateTime() ->dateTime()
->sortable(), ->sortable()
->toggleable(isToggledHiddenByDefault: true),
]) ])
->filters([ ->filters([
Tables\Filters\TrashedFilter::make(), Tables\Filters\TrashedFilter::make(),

View File

@@ -0,0 +1,120 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Exports\ItemExporter;
use App\Filament\Imports\ItemImporter;
use App\Filament\Resources\ItemResource\Pages;
use App\Models\Item;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ItemResource extends Resource
{
protected static ?string $model = Item::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('code')
->required()
->unique(ignoreRecord: true)
->minLength(6)
->autocapitalize('code'),
Forms\Components\TextInput::make('hourly_quantity')
->required()
->numeric()
->minValue(1),
Forms\Components\Textarea::make('description')
->required()
->columnSpanFull(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('code')
->sortable(),
Tables\Columns\TextColumn::make('hourly_quantity')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('description')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->importer(ItemImporter::class),
ExportAction::make()
->exporter(ItemExporter::class),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListItems::route('/'),
'create' => Pages\CreateItem::route('/create'),
'view' => Pages\ViewItem::route('/{record}'),
'edit' => Pages\EditItem::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateItem extends CreateRecord
{
protected static string $resource = ItemResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditItem extends EditRecord
{
protected static string $resource = ItemResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListItems extends ListRecords
{
protected static string $resource = ItemResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ItemResource\Pages;
use App\Filament\Resources\ItemResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewItem extends ViewRecord
{
protected static string $resource = ItemResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,117 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource\RelationManagers;
use App\Models\Line;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class LineResource extends Resource
{
protected static ?string $model = Line::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Textarea::make('name')
->required(),
// ->columnSpanFull(),
Forms\Components\Textarea::make('type')
->required(),
//->columnSpanFull(),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('block_id')
->relationship('block', 'name')
->required(),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('name')
->sortable(),
Tables\Columns\TextColumn::make('type')
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->sortable(),
Tables\Columns\TextColumn::make('block.name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListLines::route('/'),
'create' => Pages\CreateLine::route('/create'),
'view' => Pages\ViewLine::route('/{record}'),
'edit' => Pages\EditLine::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateLine extends CreateRecord
{
protected static string $resource = LineResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditLine extends EditRecord
{
protected static string $resource = LineResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListLines extends ListRecords
{
protected static string $resource = LineResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\LineResource\Pages;
use App\Filament\Resources\LineResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewLine extends ViewRecord
{
protected static string $resource = LineResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,117 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource\RelationManagers;
use App\Models\LineStop;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class LineStopResource extends Resource
{
protected static ?string $model = LineStop::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('code')
->required()
->autocapitalize(autocapitalize: 'code'),
Forms\Components\Textarea::make('reason')
->required(),
//->columnSpanFull(),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('block_id')
->relationship('block', 'name')
->required(),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('code')
->sortable(),
Tables\Columns\TextColumn::make('reason')
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->sortable(),
Tables\Columns\TextColumn::make('block.name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListLineStops::route('/'),
'create' => Pages\CreateLineStop::route('/create'),
'view' => Pages\ViewLineStop::route('/{record}'),
'edit' => Pages\EditLineStop::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateLineStop extends CreateRecord
{
protected static string $resource = LineStopResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditLineStop extends EditRecord
{
protected static string $resource = LineStopResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListLineStops extends ListRecords
{
protected static string $resource = LineStopResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\LineStopResource\Pages;
use App\Filament\Resources\LineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewLineStop extends ViewRecord
{
protected static string $resource = LineStopResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -19,6 +19,8 @@ class PlantResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack'; protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form public static function form(Form $form): Form
{ {
return $form return $form
@@ -27,17 +29,19 @@ class PlantResource extends Resource
->schema([ ->schema([
Forms\Components\TextInput::make('code') Forms\Components\TextInput::make('code')
->required() ->required()
->unique() ->unique(ignoreRecord: true)
->minValue(1000) ->numeric()
->numeric(), ->minValue(1000),
Forms\Components\Select::make('company_id') Forms\Components\Select::make('company_id')
->relationship('company', 'name') ->relationship('company', 'name')
->required(), ->required(),
Forms\Components\TextInput::make('name') Forms\Components\TextInput::make('name')
->required() ->required()
->unique(ignoreRecord: true)
->columnSpanFull(), ->columnSpanFull(),
Forms\Components\Textarea::make('address') Forms\Components\Textarea::make('address')
->required() ->required()
->unique(ignoreRecord: true)
->columnSpanFull(), ->columnSpanFull(),
]) ])
->columns(2), ->columns(2),
@@ -55,8 +59,9 @@ class PlantResource extends Resource
Tables\Columns\TextColumn::make('code') Tables\Columns\TextColumn::make('code')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('name')
->sortable(),
Tables\Columns\TextColumn::make('company.name') Tables\Columns\TextColumn::make('company.name')
->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('created_at') Tables\Columns\TextColumn::make('created_at')
->dateTime() ->dateTime()

View File

@@ -0,0 +1,144 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ProductionLineStopResource\Pages;
use App\Filament\Resources\ProductionLineStopResource\RelationManagers;
use App\Models\ProductionLineStop;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ProductionLineStopResource extends Resource
{
protected static ?string $model = ProductionLineStop::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('code_id')
->relationship('linestop', 'code')
->required(),
Forms\Components\Textarea::make('reason')
->required(),
//->columnSpanFull(),
Forms\Components\DateTimePicker::make('from_datetime')
->required(),
Forms\Components\DateTimePicker::make('to_datetime')
->required(),
Forms\Components\TextInput::make('stop_hour')
->required()
->numeric(),
Forms\Components\TextInput::make('stop_min')
->required()
->numeric(),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('block_id')
->relationship('block', 'name')
->required(),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required(),
Forms\Components\Select::make('line_id')
->relationship('line', 'name')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('linestop.code')
->sortable(),
Tables\Columns\TextColumn::make('reason')
->sortable(),
Tables\Columns\TextColumn::make('from_datetime')
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('to_datetime')
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('stop_hour')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('stop_min')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('line.name')
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->sortable(),
Tables\Columns\TextColumn::make('block.name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListProductionLineStops::route('/'),
'create' => Pages\CreateProductionLineStop::route('/create'),
'view' => Pages\ViewProductionLineStop::route('/{record}'),
'edit' => Pages\EditProductionLineStop::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ProductionLineStopResource\Pages;
use App\Filament\Resources\ProductionLineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateProductionLineStop extends CreateRecord
{
protected static string $resource = ProductionLineStopResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ProductionLineStopResource\Pages;
use App\Filament\Resources\ProductionLineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditProductionLineStop extends EditRecord
{
protected static string $resource = ProductionLineStopResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProductionLineStopResource\Pages;
use App\Filament\Resources\ProductionLineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListProductionLineStops extends ListRecords
{
protected static string $resource = ProductionLineStopResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProductionLineStopResource\Pages;
use App\Filament\Resources\ProductionLineStopResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewProductionLineStop extends ViewRecord
{
protected static string $resource = ProductionLineStopResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource\RelationManagers;
use App\Models\ProductionPlan;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ProductionPlanResource extends Resource
{
protected static ?string $model = ProductionPlan::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('plan_quantity')
->required()
->numeric()
->minValue(1),
Forms\Components\TextInput::make('production_quantity')
->required()
->numeric()
->readOnly()
->default(0),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required(),
Forms\Components\Select::make('line_id')
->relationship('line', 'name')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('plan_quantity')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('production_quantity')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('line.name')
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListProductionPlans::route('/'),
'create' => Pages\CreateProductionPlan::route('/create'),
'view' => Pages\ViewProductionPlan::route('/{record}'),
'edit' => Pages\EditProductionPlan::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateProductionPlan extends CreateRecord
{
protected static string $resource = ProductionPlanResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditProductionPlan extends EditRecord
{
protected static string $resource = ProductionPlanResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListProductionPlans extends ListRecords
{
protected static string $resource = ProductionPlanResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProductionPlanResource\Pages;
use App\Filament\Resources\ProductionPlanResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewProductionPlan extends ViewRecord
{
protected static string $resource = ProductionPlanResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,142 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Imports\ProductionQuantityImporter;
use App\Filament\Resources\ProductionQuantityResource\Pages;
use App\Filament\Resources\ProductionQuantityResource\RelationManagers;
use App\Models\ProductionQuantity;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ProductionQuantityResource extends Resource
{
protected static ?string $model = ProductionQuantity::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('plan_quantity')
->required()
->numeric(),
Forms\Components\TextInput::make('hourly_quantity')
->required()
->numeric(),
Forms\Components\TextInput::make('item_code')
->required()
->autocapitalize('item_code'),
//->columnSpanFull(),
Forms\Components\TextInput::make('serial_number')
->required()
->autocapitalize('serial_number'),
//->columnSpanFull(),
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('block_id')
->relationship('block', 'name')
->required(),
Forms\Components\Select::make('shift_id')
->relationship('shift', 'name')
->required(),
Forms\Components\Select::make('line_id')
->relationship('line', 'name')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('plan_quantity')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('hourly_quantity')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('item_code')
->sortable(),
Tables\Columns\TextColumn::make('serial_number')
->sortable(),
Tables\Columns\TextColumn::make('line.name')
->sortable(),
Tables\Columns\TextColumn::make('shift.name')
->sortable(),
Tables\Columns\TextColumn::make('block.name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
])
->headerActions([
ImportAction::make()
->importer(ProductionQuantityImporter::class),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListProductionQuantities::route('/'),
'create' => Pages\CreateProductionQuantity::route('/create'),
'view' => Pages\ViewProductionQuantity::route('/{record}'),
'edit' => Pages\EditProductionQuantity::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ProductionQuantityResource\Pages;
use App\Filament\Resources\ProductionQuantityResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateProductionQuantity extends CreateRecord
{
protected static string $resource = ProductionQuantityResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ProductionQuantityResource\Pages;
use App\Filament\Resources\ProductionQuantityResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditProductionQuantity extends EditRecord
{
protected static string $resource = ProductionQuantityResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProductionQuantityResource\Pages;
use App\Filament\Resources\ProductionQuantityResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListProductionQuantities extends ListRecords
{
protected static string $resource = ProductionQuantityResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProductionQuantityResource\Pages;
use App\Filament\Resources\ProductionQuantityResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewProductionQuantity extends ViewRecord
{
protected static string $resource = ProductionQuantityResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,120 @@
<?php
namespace App\Filament\Resources;
use App\Filament\Resources\ShiftResource\Pages;
use App\Models\Shift;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ShiftResource extends Resource
{
protected static ?string $model = Shift::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Master Entries';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plant_id')
->relationship('plant', 'name')
->required(),
Forms\Components\Select::make('block_id')
->relationship('block', 'name')
->required(),
Forms\Components\TextInput::make('name')
->required(),
Forms\Components\TimePicker::make('start_time')
->required(),
// ->native(false),
Forms\Components\TextInput::make('duration')
->required()
->inputMode('decimal')
->minValue(1),
Forms\Components\TimePicker::make('end_time')
->required(),
// ->native(false),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->numeric()
->sortable(),
Tables\Columns\TextColumn::make('name')
->sortable(),
Tables\Columns\TextColumn::make('start_time')
->sortable(),
Tables\Columns\TextColumn::make('duration')
->sortable(),
Tables\Columns\TextColumn::make('end_time'),
Tables\Columns\TextColumn::make('block.name')
->sortable(),
Tables\Columns\TextColumn::make('plant.name')
->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('deleted_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TrashedFilter::make(),
])
->actions([
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
Tables\Actions\ForceDeleteBulkAction::make(),
Tables\Actions\RestoreBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListShifts::route('/'),
'create' => Pages\CreateShift::route('/create'),
'view' => Pages\ViewShift::route('/{record}'),
'edit' => Pages\EditShift::route('/{record}/edit'),
];
}
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Filament\Resources\ShiftResource\Pages;
use App\Filament\Resources\ShiftResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord;
class CreateShift extends CreateRecord
{
protected static string $resource = ShiftResource::class;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Filament\Resources\ShiftResource\Pages;
use App\Filament\Resources\ShiftResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditShift extends EditRecord
{
protected static string $resource = ShiftResource::class;
protected function getHeaderActions(): array
{
return [
Actions\ViewAction::make(),
Actions\DeleteAction::make(),
Actions\ForceDeleteAction::make(),
Actions\RestoreAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ShiftResource\Pages;
use App\Filament\Resources\ShiftResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListShifts extends ListRecords
{
protected static string $resource = ShiftResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ShiftResource\Pages;
use App\Filament\Resources\ShiftResource;
use Filament\Actions;
use Filament\Resources\Pages\ViewRecord;
class ViewShift extends ViewRecord
{
protected static string $resource = ShiftResource::class;
protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace App\Filament\Widgets;
use Filament\Widgets\ChartWidget;
class ItemOverview extends ChartWidget
{
protected static ?string $heading = 'Chart';
protected int|string|array $columnSpan = 'full';
protected function getData(): array
{
$activeFilter = $this->filter;
$query = \DB::table('production_quantities')
->selectRaw('EXTRACT(HOUR FROM created_at) AS hour, SUM(hourly_quantity) AS total_quantity')
->whereBetween('created_at', [now()->startOfDay(), now()->endOfDay()])
->groupByRaw('EXTRACT(HOUR FROM created_at)')
->orderByRaw('EXTRACT(HOUR FROM created_at)')
->pluck('total_quantity', 'hour')
->toArray();
// Initialize data for each hour interval (8 AM - 7 PM)
$data = array_fill(8, 12, 0); // 8 AM to 7 PM (indexes 8 to 19)
// Populate actual values
// foreach ($query as $record) {
// $hour = (int) $record->hour;
// if ($hour >= 8 && $hour <= 19) {
// $data[$hour] = $record->total_quantity; // Assign only the hourly production
// }
// }
// Convert data to chart format
return [
'datasets' => [
[
'label' => 'Hourly Production',
'data' => array_values($data), // Values only
'borderColor' => 'rgba(75, 192, 192, 1)',
'backgroundColor' => 'rgba(75, 192, 192, 0.2)',
'fill' => false, // No area fill, just the line
'tension' => 0.3, // Smooth curve
],
],
'labels' => array_map(fn($h) => ($h <= 11 ? "$h AM" : ($h == 12 ? "12 PM" : ($h - 12) . " PM")), array_keys($data)),
];
// // Initialize data for each hour interval (8 AM - 7 PM)
// $data = [
// '8 AM - 9 AM' => 0, '9 AM - 10 AM' => 0, '10 AM - 11 AM' => 0, '11 AM - 12 PM' => 0,
// '12 PM - 1 PM' => 0, '1 PM - 2 PM' => 0, '2 PM - 3 PM' => 0, '3 PM - 4 PM' => 0,
// '4 PM - 5 PM' => 0, '5 PM - 6 PM' => 0, '6 PM - 7 PM' => 0, '7 PM - 8 PM' => 0,
// ];
// // Populate actual values
// foreach ($query as $record) {
// $hour = (int) $record->hour;
// if ($hour >= 8 && $hour <= 19) {
// $index = ($hour - 8); // Match hour to array index
// $labels = array_keys($data); // Get labels
// // Store only the production for that specific hour
// $data[$labels[$index]] = $record->total_quantity;
// }
// }
// // Debugging: Check if data exists
// if (empty($query) || array_sum($data) === 0) {
// \Log::info('No production data found for today.');
// }
// return [
// 'datasets' => [
// [
// 'label' => 'Production Quantities',
// 'data' => array_values($data),
// 'borderColor' => 'rgba(75, 192, 192, 1)',
// 'backgroundColor' => 'rgba(75, 192, 192, 0.2)',
// 'fill' => true,
// ],
// ],
// 'labels' => array_keys($data),
// ];
}
protected function getType(): string
{
return 'line';
}
protected function getFilters(): ?array
{
return [
'today' => 'Today',
'week' => 'Last week',
'month' => 'Last month',
'year' => 'This year',
];
}
}

33
app/Models/Block.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Block extends Model
{
use SoftDeletes;
protected $fillable = [
'name',
'plant_id',
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function shifts(): HasMany
{
return $this->hasMany(Shift::class);
}
public function lines(): HasMany
{
return $this->hasMany(Line::class);
}
}

17
app/Models/Item.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Item extends Model
{
use SoftDeletes;
protected $fillable = [
'code',
'description',
'hourly_quantity',
];
}

42
app/Models/Line.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Line extends Model
{
use SoftDeletes;
protected $fillable = [
"plant_id",
"block_id",
"shift_id",
"name",
"type",
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function shift(): BelongsTo
{
return $this->belongsTo(Shift::class);
}
public function line_stops(): HasMany
{
return $this->hasMany(LineStop::class);
}
}

36
app/Models/LineStop.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class LineStop extends Model
{
use SoftDeletes;
protected $fillable = [
"plant_id",
"block_id",
"shift_id",
"code",
"reason",
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function shift(): BelongsTo
{
return $this->belongsTo(Shift::class);
}
}

View File

@@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
class Plant extends Model class Plant extends Model
@@ -21,4 +22,9 @@ class Plant extends Model
{ {
return $this->belongsTo(Company::class); return $this->belongsTo(Company::class);
} }
public function blocks(): HasMany
{
return $this->hasMany(Block::class);
}
} }

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ProductionLineStop extends Model
{
use SoftDeletes;
protected $fillable = [
"plant_id",
"block_id",
"shift_id",
"line_id",
"code_id",
"reason",
"from_datetime",
"to_datetime",
"stop_hour",
"stop_min",
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function shift(): BelongsTo
{
return $this->belongsTo(Shift::class);
}
public function line(): BelongsTo
{
return $this->belongsTo(Line::class);
}
public function linestop(): BelongsTo
{
return $this->belongsTo(LineStop::class);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class ProductionPlan extends Model
{
use SoftDeletes;
protected $fillable = [
"plant_id",
"shift_id",
"line_id",
"plan_quantity",
"production_quantity",
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function shift(): BelongsTo
{
return $this->belongsTo(Shift::class);
}
public function line(): BelongsTo
{
return $this->belongsTo(Line::class);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ProductionQuantity extends Model
{
use SoftDeletes;
protected $fillable = [
"plant_id",
"block_id",
"shift_id",
"line_id",
"plan_quantity",
"hourly_quantity",
"item_code",
"serial_number",
];
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function shift(): BelongsTo
{
return $this->belongsTo(Shift::class);
}
public function line(): BelongsTo
{
return $this->belongsTo(Line::class);
}
}

36
app/Models/Shift.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class Shift extends Model
{
use SoftDeletes;
protected $fillable = [
'plant_id',
'block_id',
'name',
'start_time',
'duration',
'end_time',
];
// public function plant(): BelongsTo
// {
// return $this->belongsTo(Plant::class);
// }
public function block(): BelongsTo
{
return $this->belongsTo(Block::class);
}
public function plant(): BelongsTo
{
return $this->belongsTo(Plant::class);
}
}

View File

@@ -6,11 +6,12 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable class User extends Authenticatable
{ {
/** @use HasFactory<\Database\Factories\UserFactory> */ /** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable; use HasFactory, HasRoles, Notifiable;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Policies;
use App\Models\Block;
use App\Models\User;
class BlockPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->hasPermissionTo('view-any Block');
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, Block $block): bool
{
return $user->hasPermissionTo('view Block');
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->hasPermissionTo('create Block');
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Block $block): bool
{
return false;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Block $block): bool
{
return false;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Block $block): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Block $block): bool
{
return false;
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
@@ -19,6 +20,8 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot(): void public function boot(): void
{ {
// Gate::before(function ($user, $ability) {
return $user->hasRole('Super Admin') ? true : null;
});
} }
} }

View File

@@ -2,6 +2,7 @@
namespace App\Providers\Filament; namespace App\Providers\Filament;
use Althinect\FilamentSpatieRolesPermissions\FilamentSpatieRolesPermissionsPlugin;
use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession; use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents; use Filament\Http\Middleware\DisableBladeIconComponents;
@@ -24,22 +25,24 @@ class AdminPanelProvider extends PanelProvider
{ {
return $panel return $panel
->default() ->default()
->id('admin') ->id('admin')
->path('admin') ->path('admin')
->login() ->login()
->favicon(asset('/assets/crilogo1.png'))
->colors([ ->colors([
'primary' => Color::Amber, 'primary' => Color::Amber,
]) ])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([ ->pages([
Pages\Dashboard::class,
]) ])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets') ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([ // ->widgets([
Widgets\AccountWidget::class, // Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class, // Widgets\FilamentInfoWidget::class,
]) // ])
->middleware([ ->middleware([
EncryptCookies::class, EncryptCookies::class,
AddQueuedCookiesToResponse::class, AddQueuedCookiesToResponse::class,
@@ -53,6 +56,8 @@ class AdminPanelProvider extends PanelProvider
]) ])
->authMiddleware([ ->authMiddleware([
Authenticate::class, Authenticate::class,
]); ])
->databaseNotifications()
->plugin(FilamentSpatieRolesPermissionsPlugin::make());
} }
} }

View File

@@ -7,6 +7,7 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.2", "php": "^8.2",
"althinect/filament-spatie-roles-permissions": "^2.3",
"filament/filament": "^3.3", "filament/filament": "^3.3",
"laravel/framework": "^11.31", "laravel/framework": "^11.31",
"laravel/tinker": "^2.9" "laravel/tinker": "^2.9"

148
composer.lock generated
View File

@@ -4,8 +4,71 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "c2247a5e7b193701c7a41ae798179d8e", "content-hash": "292ea7e3ed35e47bcbea3972cfa9bb78",
"packages": [ "packages": [
{
"name": "althinect/filament-spatie-roles-permissions",
"version": "v2.3",
"source": {
"type": "git",
"url": "https://github.com/Althinect/filament-spatie-roles-permissions.git",
"reference": "7278e336eabd95150843c8153f680aab3f2ba131"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Althinect/filament-spatie-roles-permissions/zipball/7278e336eabd95150843c8153f680aab3f2ba131",
"reference": "7278e336eabd95150843c8153f680aab3f2ba131",
"shasum": ""
},
"require": {
"filament/filament": "^3.0",
"illuminate/support": "^9|^10|^11|^12.0",
"php": "^8.1|^8.2",
"spatie/laravel-permission": "^5.4|^6.0"
},
"require-dev": {
"laravel/pint": "^1.10",
"orchestra/testbench": "^7.0|^9.0|^10.0",
"phpunit/phpunit": "^9.0|^10.5|^11.5.3"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"FilamentSpatieRolesPermissions": "Althinect\\FilamentSpatieRolesPermissions\\FilamentSpatieRolesPermissionsFacade"
},
"providers": [
"Althinect\\FilamentSpatieRolesPermissions\\FilamentSpatieRolesPermissionsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Althinect\\FilamentSpatieRolesPermissions\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tharinda Rodrigo",
"email": "tharindarodrigo@gmail.com",
"role": "Developer"
}
],
"homepage": "https://github.com/althinect/filament-spatie-roles-permissions",
"keywords": [
"althinect",
"filament-spatie-roles-permissions"
],
"support": {
"issues": "https://github.com/Althinect/filament-spatie-roles-permissions/issues",
"source": "https://github.com/Althinect/filament-spatie-roles-permissions/tree/v2.3"
},
"time": "2025-03-01T21:25:50+00:00"
},
{ {
"name": "anourvalar/eloquent-serialize", "name": "anourvalar/eloquent-serialize",
"version": "1.2.29", "version": "1.2.29",
@@ -4885,6 +4948,89 @@
], ],
"time": "2025-02-06T14:58:20+00:00" "time": "2025-02-06T14:58:20+00:00"
}, },
{
"name": "spatie/laravel-permission",
"version": "6.16.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-permission.git",
"reference": "4fa03c06509e037a4d42c131d0f181e3e4bbd483"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/4fa03c06509e037a4d42c131d0f181e3e4bbd483",
"reference": "4fa03c06509e037a4d42c131d0f181e3e4bbd483",
"shasum": ""
},
"require": {
"illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0",
"illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0",
"illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0",
"illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0",
"php": "^8.0"
},
"require-dev": {
"laravel/passport": "^11.0|^12.0",
"laravel/pint": "^1.0",
"orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0",
"phpunit/phpunit": "^9.4|^10.1|^11.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Permission\\PermissionServiceProvider"
]
},
"branch-alias": {
"dev-main": "6.x-dev",
"dev-master": "6.x-dev"
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Spatie\\Permission\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Permission handling for Laravel 8.0 and up",
"homepage": "https://github.com/spatie/laravel-permission",
"keywords": [
"acl",
"laravel",
"permission",
"permissions",
"rbac",
"roles",
"security",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-permission/issues",
"source": "https://github.com/spatie/laravel-permission/tree/6.16.0"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2025-02-28T20:29:57+00:00"
},
{ {
"name": "symfony/clock", "name": "symfony/clock",
"version": "v7.2.0", "version": "v7.2.0",

View File

@@ -0,0 +1,218 @@
<?php
return [
'resources' => [
'PermissionResource' => \Althinect\FilamentSpatieRolesPermissions\Resources\PermissionResource::class,
'RoleResource' => \Althinect\FilamentSpatieRolesPermissions\Resources\RoleResource::class,
],
'preload_roles' => true,
'preload_permissions' => true,
'navigation_section_group' => 'filament-spatie-roles-permissions::filament-spatie.section.roles_and_permissions', // Default uses language constant
// 'team_model' => \App\Models\Team::class,
'scope_to_tenant' => true,
'super_admin_role_name' => 'Super Admin',
/*
* Set as false to remove from navigation.
*/
'should_register_on_navigation' => [
'permissions' => true,
'roles' => true,
],
'should_show_permissions_for_roles' => true,
/*
* Set as true to use simple modal resource.
*/
'should_use_simple_modal_resource' => [
'permissions' => false,
'roles' => false,
],
/*
* Set as true to remove empty state actions.
*/
'should_remove_empty_state_actions' => [
'permissions' => false,
'roles' => false,
],
/**
* Set to true to redirect to the resource index instead of the view
*/
'should_redirect_to_index' => [
'permissions' => [
'after_create' => false,
'after_edit' => false,
],
'roles' => [
'after_create' => false,
'after_edit' => false,
],
],
/**
* Set to true to display relation managers in the resources
*/
'should_display_relation_managers' => [
'permissions' => true,
'users' => true,
'roles' => true,
],
/*
* If you want to place the Resource in a Cluster, then set the required Cluster class.
* Eg. \App\Filament\Clusters\Cluster::class
*/
'clusters' => [
'permissions' => null,
'roles' => null,
],
'guard_names' => [
'web' => 'web',
'api' => 'api',
],
'toggleable_guard_names' => [
'roles' => [
'isToggledHiddenByDefault' => true,
],
'permissions' => [
'isToggledHiddenByDefault' => true,
],
],
'default_guard_name' => null,
// if false guard option will not be show on screen. You should set a default_guard_name in this case
'should_show_guard' => true,
'model_filter_key' => 'return \'%\'.$value;', // Eg: 'return \'%\'.$key.'\%\';'
'user_name_column' => 'name',
/*
* If user_name_column is an accessor from a model, then list columns to search.
* Default: null, will search by user_name_column
*
* Example:
*
* 'user_name_searchable_columns' => ['first_name', 'last_name']
*
* and in your model:
*
* public function getFullNameAttribute() {
* return $this->first_name . ' ' . $this->last_name;
* }
*
*/
'user_name_searchable_columns' => ['name'],
/*
* Icons to use for navigation
*/
'icons' => [
'role_navigation' => 'heroicon-o-lock-closed',
'permission_navigation' => 'heroicon-o-lock-closed',
],
/*
* Navigation items order - int value, false restores the default position
*/
'sort' => [
'role_navigation' => false,
'permission_navigation' => false,
],
'generator' => [
'guard_names' => [
'web',
'api',
],
'permission_affixes' => [
/*
* Permissions Aligned with Policies.
* DO NOT change the keys unless the genericPolicy.stub is published and altered accordingly
*/
'viewAnyPermission' => 'view-any',
'viewPermission' => 'view',
'createPermission' => 'create',
'updatePermission' => 'update',
'deletePermission' => 'delete',
'deleteAnyPermission' => 'delete-any',
'replicatePermission' => 'replicate',
'restorePermission' => 'restore',
'restoreAnyPermission' => 'restore-any',
'reorderPermission' => 'reorder',
'forceDeletePermission' => 'force-delete',
'forceDeleteAnyPermission' => 'force-delete-any',
],
/*
* returns the "name" for the permission.
*
* $permission which is an iteration of [permission_affixes] ,
* $model The model to which the $permission will be concatenated
*
* Eg: 'permission_name' => 'return $permissionAffix . ' ' . Str::kebab($modelName),
*
* Note: If you are changing the "permission_name" , It's recommended to run with --clean to avoid duplications
*/
'permission_name' => 'return $permissionAffix . \' \' . $modelName;',
/*
* Permissions will be generated for the models associated with the respective Filament Resources
*/
'discover_models_through_filament_resources' => false,
/*
* Include directories which consists of models.
*/
'model_directories' => [
app_path('Models'),
// app_path('Domains/Forum')
],
/*
* Define custom_models
*/
'custom_models' => [
//
],
/*
* Define excluded_models
*/
'excluded_models' => [
//
],
'excluded_policy_models' => [
\App\Models\User::class,
],
/*
* Define any other permission that should be synced with the DB
*/
'custom_permissions' => [
// 'view-log'
],
'user_model' => \App\Models\User::class,
'policies_namespace' => 'App\Policies',
],
];

89
config/filament.php Normal file
View File

@@ -0,0 +1,89 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Broadcasting
|--------------------------------------------------------------------------
|
| By uncommenting the Laravel Echo configuration, you may connect Filament
| to any Pusher-compatible websockets server.
|
| This will allow your users to receive real-time notifications.
|
*/
'broadcasting' => [
// 'echo' => [
// 'broadcaster' => 'pusher',
// 'key' => env('VITE_PUSHER_APP_KEY'),
// 'cluster' => env('VITE_PUSHER_APP_CLUSTER'),
// 'wsHost' => env('VITE_PUSHER_HOST'),
// 'wsPort' => env('VITE_PUSHER_PORT'),
// 'wssPort' => env('VITE_PUSHER_PORT'),
// 'authEndpoint' => '/broadcasting/auth',
// 'disableStats' => true,
// 'encrypted' => true,
// 'forceTLS' => true,
// ],
],
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| This is the storage disk Filament will use to store files. You may use
| any of the disks defined in the `config/filesystems.php`.
|
*/
'default_filesystem_disk' => env('FILAMENT_FILESYSTEM_DISK', 'public'),
/*
|--------------------------------------------------------------------------
| Assets Path
|--------------------------------------------------------------------------
|
| This is the directory where Filament's assets will be published to. It
| is relative to the `public` directory of your Laravel application.
|
| After changing the path, you should run `php artisan filament:assets`.
|
*/
'assets_path' => null,
/*
|--------------------------------------------------------------------------
| Cache Path
|--------------------------------------------------------------------------
|
| This is the directory that Filament will use to store cache files that
| are used to optimize the registration of components.
|
| After changing the path, you should run `php artisan filament:cache-components`.
|
*/
'cache_path' => base_path('bootstrap/cache/filament'),
/*
|--------------------------------------------------------------------------
| Livewire Loading Delay
|--------------------------------------------------------------------------
|
| This sets the delay before loading indicators appear.
|
| Setting this to 'none' makes indicators appear immediately, which can be
| desirable for high-latency connections. Setting it to 'default' applies
| Livewire's standard 200ms delay.
|
*/
'livewire_loading_delay' => 'default',
];

202
config/permission.php Normal file
View File

@@ -0,0 +1,202 @@
<?php
return [
'models' => [
/*
* When using the "HasPermissions" trait from this package, we need to know which
* Eloquent model should be used to retrieve your permissions. Of course, it
* is often just the "Permission" model but you may use whatever you like.
*
* The model you want to use as a Permission model needs to implement the
* `Spatie\Permission\Contracts\Permission` contract.
*/
'permission' => Spatie\Permission\Models\Permission::class,
/*
* When using the "HasRoles" trait from this package, we need to know which
* Eloquent model should be used to retrieve your roles. Of course, it
* is often just the "Role" model but you may use whatever you like.
*
* The model you want to use as a Role model needs to implement the
* `Spatie\Permission\Contracts\Role` contract.
*/
'role' => Spatie\Permission\Models\Role::class,
],
'table_names' => [
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your roles. We have chosen a basic
* default value but you may easily change it to any table you like.
*/
'roles' => 'roles',
/*
* When using the "HasPermissions" trait from this package, we need to know which
* table should be used to retrieve your permissions. We have chosen a basic
* default value but you may easily change it to any table you like.
*/
'permissions' => 'permissions',
/*
* When using the "HasPermissions" trait from this package, we need to know which
* table should be used to retrieve your models permissions. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'model_has_permissions' => 'model_has_permissions',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your models roles. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'model_has_roles' => 'model_has_roles',
/*
* When using the "HasRoles" trait from this package, we need to know which
* table should be used to retrieve your roles permissions. We have chosen a
* basic default value but you may easily change it to any table you like.
*/
'role_has_permissions' => 'role_has_permissions',
],
'column_names' => [
/*
* Change this if you want to name the related pivots other than defaults
*/
'role_pivot_key' => null, // default 'role_id',
'permission_pivot_key' => null, // default 'permission_id',
/*
* Change this if you want to name the related model primary key other than
* `model_id`.
*
* For example, this would be nice if your primary keys are all UUIDs. In
* that case, name this `model_uuid`.
*/
'model_morph_key' => 'model_id',
/*
* Change this if you want to use the teams feature and your related model's
* foreign key is other than `team_id`.
*/
'team_foreign_key' => 'team_id',
],
/*
* When set to true, the method for checking permissions will be registered on the gate.
* Set this to false if you want to implement custom logic for checking permissions.
*/
'register_permission_check_method' => true,
/*
* When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
* this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
* NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
*/
'register_octane_reset_listener' => false,
/*
* Events will fire when a role or permission is assigned/unassigned:
* \Spatie\Permission\Events\RoleAttached
* \Spatie\Permission\Events\RoleDetached
* \Spatie\Permission\Events\PermissionAttached
* \Spatie\Permission\Events\PermissionDetached
*
* To enable, set to true, and then create listeners to watch these events.
*/
'events_enabled' => false,
/*
* Teams Feature.
* When set to true the package implements teams using the 'team_foreign_key'.
* If you want the migrations to register the 'team_foreign_key', you must
* set this to true before doing the migration.
* If you already did the migration then you must make a new migration to also
* add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
* (view the latest version of this package's migration file)
*/
'teams' => false,
/*
* The class to use to resolve the permissions team id
*/
'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class,
/*
* Passport Client Credentials Grant
* When set to true the package will use Passports Client to check permissions
*/
'use_passport_client_credentials' => false,
/*
* When set to true, the required permission names are added to exception messages.
* This could be considered an information leak in some contexts, so the default
* setting is false here for optimum safety.
*/
'display_permission_in_exception' => false,
/*
* When set to true, the required role names are added to exception messages.
* This could be considered an information leak in some contexts, so the default
* setting is false here for optimum safety.
*/
'display_role_in_exception' => false,
/*
* By default wildcard permission lookups are disabled.
* See documentation to understand supported syntax.
*/
'enable_wildcard_permission' => false,
/*
* The class to use for interpreting wildcard permissions.
* If you need to modify delimiters, override the class and specify its name here.
*/
// 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class,
/* Cache-specific settings */
'cache' => [
/*
* By default all permissions are cached for 24 hours to speed up performance.
* When permissions or roles are updated the cache is flushed automatically.
*/
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
/*
* The cache key used to store all permissions.
*/
'key' => 'spatie.permission.cache',
/*
* You may optionally indicate a specific cache driver to use for permission and
* role caching using any of the `store` drivers listed in the cache.php config
* file. Using 'default' here means to use the `default` set in cache.php.
*/
'store' => 'default',
],
];

View File

@@ -13,7 +13,7 @@ return new class extends Migration
$sql = <<<'SQL' $sql = <<<'SQL'
CREATE TABLE companies ( CREATE TABLE companies (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY, id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL UNIQUE, name CITEXT NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(),

View File

@@ -15,10 +15,10 @@ return new class extends Migration
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY, id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
code INT NOT NULL CHECK (code >= 1000) UNIQUE, code INT NOT NULL CHECK (code >= 1000) UNIQUE,
company_id INT NOT NULL, company_id BIGINT NOT NULL,
name TEXT NOT NULL UNIQUE, -- CITEXT use extension name CITEXT NOT NULL UNIQUE, -- CITEXT use extension
address TEXT NOT NULL, address CITEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
@@ -26,7 +26,6 @@ return new class extends Migration
FOREIGN KEY (company_id) REFERENCES companies (id) FOREIGN KEY (company_id) REFERENCES companies (id)
); );
SQL; SQL;
DB::statement($sql); DB::statement($sql);

View File

@@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE blocks (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
name CITEXT NOT NULL,
plant_id BIGINT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
UNIQUE (name, plant_id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('blocks');
}
};

View File

@@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE shifts (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
name CITEXT NOT NULL,
block_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
start_time TIME NOT NULL,
duration DECIMAL NOT NULL,
end_time TIME NOT NULL, --GENERATED ALWAYS AS (start_time + (duration * INTERVAL '1 hour')) STORED,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
UNIQUE (name, block_id, plant_id),
FOREIGN KEY (block_id) REFERENCES blocks (id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('shifts');
}
};

View File

@@ -0,0 +1,47 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE items (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
line_id BIGINT NOT NULL,
block_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
code CITEXT NOT NULL CHECK (LENGTH(code) >= 6),
description CITEXT NOT NULL,
hourly_quantity INT NOT NULL CHECK (hourly_quantity > 0),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
UNIQUE (code, line_id, block_id, plant_id),
FOREIGN KEY (line_id) REFERENCES lines (id),
FOREIGN KEY (block_id) REFERENCES blocks (id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('items');
}
};

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
ALTER TABLE shifts
ADD status TEXT NOT NULL DEFAULT 'Active';
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('notifications', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('type');
$table->morphs('notifiable');
$table->json('data');
$table->timestamp('read_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('notifications');
}
};

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('imports', function (Blueprint $table) {
$table->id();
$table->timestamp('completed_at')->nullable();
$table->string('file_name');
$table->string('file_path');
$table->string('importer');
$table->unsignedInteger('processed_rows')->default(0);
$table->unsignedInteger('total_rows');
$table->unsignedInteger('successful_rows')->default(0);
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('imports');
}
};

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('exports', function (Blueprint $table) {
$table->id();
$table->timestamp('completed_at')->nullable();
$table->string('file_disk');
$table->string('file_name')->nullable();
$table->string('exporter');
$table->unsignedInteger('processed_rows')->default(0);
$table->unsignedInteger('total_rows');
$table->unsignedInteger('successful_rows')->default(0);
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('exports');
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('failed_import_rows', function (Blueprint $table) {
$table->id();
$table->json('data');
$table->foreignId('import_id')->constrained()->cascadeOnDelete();
$table->text('validation_error')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('failed_import_rows');
}
};

View File

@@ -0,0 +1,140 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$teams = config('permission.teams');
$tableNames = config('permission.table_names');
$columnNames = config('permission.column_names');
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
Schema::create($tableNames['permissions'], static function (Blueprint $table) {
// $table->engine('InnoDB');
$table->bigIncrements('id'); // permission id
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
$table->timestamps();
$table->unique(['name', 'guard_name']);
});
Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) {
// $table->engine('InnoDB');
$table->bigIncrements('id'); // role id
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
}
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
$table->timestamps();
if ($teams || config('permission.testing')) {
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
} else {
$table->unique(['name', 'guard_name']);
}
});
Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
$table->unsignedBigInteger($pivotPermission);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
$table->foreign($pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
} else {
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
}
});
Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
$table->unsignedBigInteger($pivotRole);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
$table->foreign($pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
} else {
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
}
});
Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
$table->unsignedBigInteger($pivotPermission);
$table->unsignedBigInteger($pivotRole);
$table->foreign($pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
$table->foreign($pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
});
app('cache')
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
->forget(config('permission.cache.key'));
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$tableNames = config('permission.table_names');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
}
Schema::drop($tableNames['role_has_permissions']);
Schema::drop($tableNames['model_has_roles']);
Schema::drop($tableNames['model_has_permissions']);
Schema::drop($tableNames['roles']);
Schema::drop($tableNames['permissions']);
}
};

View File

@@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE line_stops (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
shift_id BIGINT NOT NULL,
block_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
code TEXT NOT NULL,
reason TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
UNIQUE (code, shift_id, block_id, plant_id),
FOREIGN KEY (shift_id) REFERENCES shifts (id),
FOREIGN KEY (block_id) REFERENCES blocks (id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('line_stops');
}
};

View File

@@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE lines (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
shift_id BIGINT NOT NULL,
block_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
name TEXT NOT NULL,
type TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
UNIQUE (name, shift_id, block_id, plant_id),
FOREIGN KEY (shift_id) REFERENCES shifts (id),
FOREIGN KEY (block_id) REFERENCES blocks (id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('lines');
}
};

View File

@@ -0,0 +1,44 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE production_plans (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
line_id BIGINT NOT NULL,
shift_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
plan_quantity INT NOT NULL CHECK (plan_quantity > 0),
production_quantity INT NOT NULL DEFAULT (0),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
FOREIGN KEY (line_id) REFERENCES lines (id),
FOREIGN KEY (shift_id) REFERENCES shifts (id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('production_plans');
}
};

View File

@@ -0,0 +1,52 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE production_line_stops (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
line_id BIGINT NOT NULL,
shift_id BIGINT NOT NULL,
block_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
code_id BIGINT NOT NULL,
reason TEXT NOT NULL,
from_datetime TIMESTAMP NOT NULL,
to_datetime TIMESTAMP NOT NULL,
stop_hour INT NOT NULL,
stop_min INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
FOREIGN KEY (line_id) REFERENCES lines (id),
FOREIGN KEY (shift_id) REFERENCES shifts (id),
FOREIGN KEY (block_id) REFERENCES blocks (id),
FOREIGN KEY (plant_id) REFERENCES plants (id),
FOREIGN KEY (code_id) REFERENCES line_stops (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('production_line_stops');
}
};

View File

@@ -0,0 +1,48 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$sql = <<<'SQL'
CREATE TABLE production_quantities (
id BIGINT GENERATED always AS IDENTITY PRIMARY KEY,
line_id BIGINT NOT NULL,
shift_id BIGINT NOT NULL,
block_id BIGINT NOT NULL,
plant_id BIGINT NOT NULL,
item_code TEXT NOT NULL,
serial_number TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP,
UNIQUE (item_code, serial_number),
FOREIGN KEY (line_id) REFERENCES lines (id),
FOREIGN KEY (shift_id) REFERENCES shifts (id),
FOREIGN KEY (block_id) REFERENCES blocks (id),
FOREIGN KEY (plant_id) REFERENCES plants (id)
);
SQL;
DB::statement($sql);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('production_quantities');
}
};

View File

@@ -2,7 +2,6 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents; // use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
@@ -13,11 +12,7 @@ class DatabaseSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
// User::factory(10)->create(); $this->call(RoleSeeder::class);
$this->call(UserSeeder::class);
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
} }
} }

View File

@@ -0,0 +1,20 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class RoleSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Role::create([
'name' => 'Super Admin',
'guard_name' => 'web',
]);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$user1 = User::create([
'name' => 'Admin',
'email' => 'admin@cripumps.com',
'password' => bcrypt('admin'),
]);
$user1->assignRole('Super Admin');
$user2 = User::create([
'name' => 'Admin',
'email' => 'admin@cripumps.com',
'password' => bcrypt('admin'),
]);
$user2->assignRole('Super Admin');
User::factory()->count(10)->create();
}
}

1
public/assets Symbolic link
View File

@@ -0,0 +1 @@
/home/iot-dev/projects/pds/storage/app/public

View File

@@ -0,0 +1,17 @@
@if (isset($data))
<script>
window.filamentData = @js($data)
</script>
@endif
@foreach ($assets as $asset)
@if (! $asset->isLoadedOnRequest())
{{ $asset->getHtml() }}
@endif
@endforeach
<style>
:root {
@foreach ($cssVariables ?? [] as $cssVariableName => $cssVariableValue) --{{ $cssVariableName }}:{{ $cssVariableValue }}; @endforeach
}
</style>

View File

@@ -0,0 +1,64 @@
@php
use Filament\Support\Enums\Alignment;
@endphp
@props([
'actions' => [],
'alignment' => Alignment::Start,
'fullWidth' => false,
])
@php
if (is_array($actions)) {
$actions = array_filter(
$actions,
fn ($action): bool => $action->isVisible(),
);
}
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
}
$hasActions = false;
$hasSlot = ! \Filament\Support\is_slot_empty($slot);
$actionsAreHtmlable = $actions instanceof \Illuminate\Contracts\Support\Htmlable;
if ($hasSlot) {
$hasActions = true;
} elseif ($actionsAreHtmlable) {
$hasActions = ! \Filament\Support\is_slot_empty($actions);
} else {
$hasActions = filled($actions);
}
@endphp
@if ($hasActions)
<div
{{
$attributes->class([
'fi-ac gap-3',
'flex flex-wrap items-center' => ! $fullWidth,
match ($alignment) {
Alignment::Start, Alignment::Left => 'justify-start',
Alignment::Center => 'justify-center',
Alignment::End, Alignment::Right => 'flex-row-reverse',
Alignment::Between, Alignment::Justify => 'justify-between',
default => $alignment,
} => ! $fullWidth,
'grid grid-cols-[repeat(auto-fit,minmax(0,1fr))]' => $fullWidth,
])
}}
>
@if ($hasSlot)
{{ $slot }}
@elseif ($actionsAreHtmlable)
{{ $actions }}
@else
@foreach ($actions as $action)
{{ $action }}
@endforeach
@endif
</div>
@endif

View File

@@ -0,0 +1,21 @@
@props([
'circular' => true,
'size' => 'md',
])
<img
{{
$attributes
->class([
'fi-avatar object-cover object-center',
'rounded-md' => ! $circular,
'fi-circular rounded-full' => $circular,
match ($size) {
'sm' => 'h-6 w-6',
'md' => 'h-8 w-8',
'lg' => 'h-10 w-10',
default => $size,
},
])
}}
/>

View File

@@ -0,0 +1,238 @@
@php
use Filament\Support\Enums\ActionSize;
use Filament\Support\Enums\IconPosition;
use Filament\Support\Enums\IconSize;
@endphp
@props([
'color' => 'primary',
'deleteButton' => null,
'disabled' => false,
'form' => null,
'formId' => null,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconPosition' => IconPosition::Before,
'iconSize' => IconSize::Small,
'keyBindings' => null,
'loadingIndicator' => true,
'size' => ActionSize::Medium,
'spaMode' => null,
'tag' => 'span',
'target' => null,
'tooltip' => null,
'type' => 'button',
])
@php
if (! $iconPosition instanceof IconPosition) {
$iconPosition = filled($iconPosition) ? (IconPosition::tryFrom($iconPosition) ?? $iconPosition) : null;
}
if (! $size instanceof ActionSize) {
$size = filled($size) ? (ActionSize::tryFrom($size) ?? $size) : null;
}
if (! $iconSize instanceof IconSize) {
$iconSize = filled($iconSize) ? (IconSize::tryFrom($iconSize) ?? $iconSize) : null;
}
$isDeletable = count($deleteButton?->attributes->getAttributes() ?? []) > 0;
$iconClasses = \Illuminate\Support\Arr::toCssClasses([
'fi-badge-icon h-4 w-4',
match ($iconSize) {
IconSize::Small => 'h-4 w-4',
IconSize::Medium => 'h-5 w-5',
IconSize::Large => 'h-6 w-6',
default => $iconSize,
},
match ($color) {
'gray' => 'text-gray-400 dark:text-gray-500',
default => 'text-custom-500',
},
]);
$iconStyles = \Illuminate\Support\Arr::toCssStyles([
\Filament\Support\get_color_css_variables(
$color,
shades: [500],
alias: 'badge.icon',
) => $color !== 'gray',
]);
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasLoadingIndicator = filled($wireTarget) || ($type === 'submit' && filled($form));
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
<{{ $tag }}
@if ($tag === 'a')
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($keyBindings || $hasTooltip)
x-data="{}"
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->merge([
'disabled' => $disabled,
'form' => $tag === 'button' ? $formId : null,
'type' => $tag === 'button' ? $type : null,
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
], escape: false)
->class([
'fi-badge flex items-center justify-center gap-x-1 rounded-md text-xs font-medium ring-1 ring-inset',
'pointer-events-none opacity-70' => $disabled,
match ($size) {
ActionSize::ExtraSmall => 'px-0.5 min-w-[theme(spacing.4)] tracking-tighter',
ActionSize::Small => 'px-1.5 min-w-[theme(spacing.5)] py-0.5 tracking-tight',
ActionSize::Medium, ActionSize::Large, ActionSize::ExtraLarge => 'px-2 min-w-[theme(spacing.6)] py-1',
default => $size,
},
match ($color) {
'gray' => 'bg-gray-50 text-gray-600 ring-gray-600/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20',
default => 'fi-color-custom bg-custom-50 text-custom-600 ring-custom-600/10 dark:bg-custom-400/10 dark:text-custom-400 dark:ring-custom-400/30',
},
is_string($color) ? "fi-color-{$color}" : null,
])
->style([
\Filament\Support\get_color_css_variables(
$color,
shades: [
50,
400,
600,
],
alias: 'badge',
) => $color !== 'gray',
])
}}
>
@if ($iconPosition === IconPosition::Before)
@if ($icon)
<x-filament::icon
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'alias' => $iconAlias,
'icon' => $icon,
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : null,
])
)
->class([$iconClasses])
->style([$iconStyles])
"
/>
@endif
@if ($hasLoadingIndicator)
<x-filament::loading-indicator
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])
)
->class([$iconClasses])
->style([$iconStyles])
"
/>
@endif
@endif
<span class="grid">
<span class="truncate">
{{ $slot }}
</span>
</span>
@if ($isDeletable)
<button
type="button"
{{
$deleteButton
->attributes
->except(['label'])
->class([
'fi-badge-delete-button -my-1 -me-2 -ms-1 flex items-center justify-center p-1 outline-none transition duration-75',
match ($color) {
'gray' => 'text-gray-700/50 hover:text-gray-700/75 focus-visible:text-gray-700/75 dark:text-gray-300/50 dark:hover:text-gray-300/75 dark:focus-visible:text-gray-300/75',
default => 'text-custom-700/50 hover:text-custom-700/75 focus-visible:text-custom-700/75 dark:text-custom-300/50 dark:hover:text-custom-300/75 dark:focus-visible:text-custom-300/75',
},
])
->style([
\Filament\Support\get_color_css_variables(
$color,
shades: [300, 700],
alias: 'badge.delete-button',
) => $color !== 'gray',
])
}}
>
<x-filament::icon
alias="badge.delete-button"
icon="heroicon-m-x-mark"
class="h-3.5 w-3.5"
/>
@if (filled($label = $deleteButton->attributes->get('label')))
<span class="sr-only">
{{ $label }}
</span>
@endif
</button>
@elseif ($iconPosition === IconPosition::After)
@if ($icon)
<x-filament::icon
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'alias' => $iconAlias,
'icon' => $icon,
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : null,
])
)
->class([$iconClasses])
->style([$iconStyles])
"
/>
@endif
@if ($hasLoadingIndicator)
<x-filament::loading-indicator
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])
)
->class([$iconClasses])
->style([$iconStyles])
"
/>
@endif
@endif
</{{ $tag }}>

View File

@@ -0,0 +1,50 @@
@props([
'breadcrumbs' => [],
])
@php
$iconClasses = 'fi-breadcrumbs-item-separator flex h-5 w-5 text-gray-400 dark:text-gray-500';
$itemLabelClasses = 'fi-breadcrumbs-item-label text-sm font-medium text-gray-500 dark:text-gray-400';
@endphp
<nav {{ $attributes->class(['fi-breadcrumbs']) }}>
<ol class="fi-breadcrumbs-list flex flex-wrap items-center gap-x-2">
@foreach ($breadcrumbs as $url => $label)
<li class="fi-breadcrumbs-item flex items-center gap-x-2">
@if (! $loop->first)
<x-filament::icon
alias="breadcrumbs.separator"
icon="heroicon-m-chevron-right"
@class([
$iconClasses,
'rtl:hidden',
])
/>
<x-filament::icon
{{-- @deprecated Use `breadcrubs.separator.rtl` instead of `breadcrumbs.separator` for RTL. --}}
:alias="['breadcrumbs.separator.rtl', 'breadcrumbs.separator']"
icon="heroicon-m-chevron-left"
@class([
$iconClasses,
'ltr:hidden',
])
/>
@endif
@if (is_int($url))
<span class="{{ $itemLabelClasses }}">
{{ $label }}
</span>
@else
<a
{{ \Filament\Support\generate_href_html($url) }}
class="{{ $itemLabelClasses }} transition duration-75 hover:text-gray-700 dark:hover:text-gray-200"
>
{{ $label }}
</a>
@endif
</li>
@endforeach
</ol>
</nav>

View File

@@ -0,0 +1,9 @@
<div
{{
$attributes->class([
'fi-btn-group grid grid-flow-col rounded-lg shadow-sm ring-1 ring-gray-950/10 dark:ring-white/20',
])
}}
>
{{ $slot }}
</div>

View File

@@ -0,0 +1,332 @@
@php
use Filament\Support\Enums\ActionSize;
use Filament\Support\Enums\IconPosition;
use Filament\Support\Enums\IconSize;
@endphp
@props([
'badge' => null,
'badgeColor' => 'primary',
'badgeSize' => 'xs',
'color' => 'primary',
'disabled' => false,
'form' => null,
'formId' => null,
'grouped' => false,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconPosition' => IconPosition::Before,
'iconSize' => null,
'keyBindings' => null,
'labeledFrom' => null,
'labelSrOnly' => false,
'loadingIndicator' => true,
'outlined' => false,
'size' => ActionSize::Medium,
'spaMode' => null,
'tag' => 'button',
'target' => null,
'tooltip' => null,
'type' => 'button',
])
@php
if (! $iconPosition instanceof IconPosition) {
$iconPosition = filled($iconPosition) ? (IconPosition::tryFrom($iconPosition) ?? $iconPosition) : null;
}
if (! $size instanceof ActionSize) {
$size = filled($size) ? (ActionSize::tryFrom($size) ?? $size) : null;
}
$iconSize ??= match ($size) {
ActionSize::ExtraSmall, ActionSize::Small => IconSize::Small,
default => IconSize::Medium,
};
if (! $iconSize instanceof IconSize) {
$iconSize = filled($iconSize) ? (IconSize::tryFrom($iconSize) ?? $iconSize) : null;
}
$buttonClasses = \Illuminate\Support\Arr::toCssClasses([
...[
'fi-btn relative grid-flow-col items-center justify-center font-semibold outline-none transition duration-75 focus-visible:ring-2',
'pointer-events-none opacity-70' => $disabled,
'rounded-lg' => ! $grouped,
'flex-1 [&:nth-child(1_of_.fi-btn)]:rounded-s-lg [&:nth-last-child(1_of_.fi-btn)]:rounded-e-lg [&:not(:nth-child(1_of_.fi-btn))]:shadow-[-1px_0_0_0_theme(colors.gray.200)] [&:not(:nth-last-child(1_of_.fi-btn))]:me-px dark:[&:not(:nth-child(1_of_.fi-btn))]:shadow-[-1px_0_0_0_theme(colors.white/20%)]' => $grouped,
'cursor-pointer' => $tag === 'label',
match ($color) {
'gray' => null,
default => 'fi-color-custom',
},
// @deprecated `fi-btn-color-*` has been replaced by `fi-color-*` and `fi-color-custom`.
is_string($color) ? "fi-btn-color-{$color}" : null,
is_string($color) ? "fi-color-{$color}" : null,
($size instanceof ActionSize) ? "fi-size-{$size->value}" : null,
// @deprecated `fi-btn-size-*` has been replaced by `fi-size-*`.
($size instanceof ActionSize) ? "fi-btn-size-{$size->value}" : null,
match ($size) {
ActionSize::ExtraSmall => 'gap-1 px-2 py-1.5 text-xs',
ActionSize::Small => 'gap-1 px-2.5 py-1.5 text-sm',
ActionSize::Medium => 'gap-1.5 px-3 py-2 text-sm',
ActionSize::Large => 'gap-1.5 px-3.5 py-2.5 text-sm',
ActionSize::ExtraLarge => 'gap-1.5 px-4 py-3 text-sm',
default => $size,
},
'hidden' => $labeledFrom,
match ($labeledFrom) {
'sm' => 'sm:inline-grid',
'md' => 'md:inline-grid',
'lg' => 'lg:inline-grid',
'xl' => 'xl:inline-grid',
'2xl' => '2xl:inline-grid',
default => 'inline-grid',
},
],
...(
$outlined ?
[
'fi-btn-outlined ring-1',
match ($color) {
'gray' => 'text-gray-950 ring-gray-300 hover:bg-gray-400/10 focus-visible:ring-gray-400/40 dark:text-white dark:ring-gray-700',
default => 'text-custom-600 ring-custom-600 hover:bg-custom-400/10 dark:text-custom-400 dark:ring-custom-500',
},
] :
[
'shadow-sm' => ! $grouped,
'bg-white text-gray-950 hover:bg-gray-50 dark:bg-white/5 dark:text-white dark:hover:bg-white/10' => ($color === 'gray') || ($tag === 'label'),
'ring-1 ring-gray-950/10 dark:ring-white/20' => (($color === 'gray') || ($tag === 'label')) && (! $grouped),
'bg-custom-600 text-white hover:bg-custom-500 focus-visible:ring-custom-500/50 dark:bg-custom-500 dark:hover:bg-custom-400 dark:focus-visible:ring-custom-400/50' => ($color !== 'gray') && ($tag !== 'label'),
'[input:checked+&]:bg-custom-600 [input:checked+&]:text-white [input:checked+&]:ring-0 [input:checked+&]:hover:bg-custom-500 dark:[input:checked+&]:bg-custom-500 dark:[input:checked+&]:hover:bg-custom-400 [input:checked:focus-visible+&]:ring-custom-500/50 dark:[input:checked:focus-visible+&]:ring-custom-400/50 [input:focus-visible+&]:z-10 [input:focus-visible+&]:ring-2 [input:focus-visible+&]:ring-gray-950/10 dark:[input:focus-visible+&]:ring-white/20' => ($color !== 'gray') && ($tag === 'label'),
'[input:checked+&]:bg-gray-400 [input:checked+&]:text-white [input:checked+&]:ring-0 [input:checked+&]:hover:bg-gray-300 dark:[input:checked+&]:bg-gray-600 dark:[input:checked+&]:hover:bg-gray-500' => ($color === 'gray'),
]
),
]);
$buttonStyles = \Illuminate\Support\Arr::toCssStyles([
\Filament\Support\get_color_css_variables(
$color,
shades: [400, 500, 600],
alias: 'button',
) => $color !== 'gray',
]);
$iconClasses = \Illuminate\Support\Arr::toCssClasses([
'fi-btn-icon transition duration-75',
match ($iconSize) {
IconSize::Small => 'h-4 w-4',
IconSize::Medium => 'h-5 w-5',
IconSize::Large => 'h-6 w-6',
default => $iconSize,
},
'text-gray-400 dark:text-gray-500' => ($color === 'gray') || ($tag === 'label'),
'text-white' => ($color !== 'gray') && ($tag !== 'label') && (! $outlined),
'[:checked+*>&]:text-white' => $tag === 'label',
]);
$badgeContainerClasses = 'fi-btn-badge-ctn absolute start-full top-0 z-[1] w-max -translate-x-1/2 -translate-y-1/2 rounded-md bg-white dark:bg-gray-900 rtl:translate-x-1/2';
$labelClasses = \Illuminate\Support\Arr::toCssClasses([
'fi-btn-label',
'sr-only' => $labelSrOnly,
]);
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasFormProcessingLoadingIndicator = $type === 'submit' && filled($form);
$hasLoadingIndicator = filled($wireTarget) || $hasFormProcessingLoadingIndicator;
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
@if ($labeledFrom)
<x-filament::icon-button
:badge="$badge"
:badge-color="$badgeColor"
:color="$color"
:disabled="$disabled"
:form="$form"
:form-id="$formId"
:href="$href"
:icon="$icon"
:icon-alias="$iconAlias"
:icon-size="$iconSize"
:key-bindings="$keyBindings"
:label="$slot"
:size="$size"
:tag="$tag"
:target="$target"
:tooltip="$tooltip"
:type="$type"
:class="
match ($labeledFrom) {
'sm' => 'sm:hidden',
'md' => 'md:hidden',
'lg' => 'lg:hidden',
'xl' => 'xl:hidden',
'2xl' => '2xl:hidden',
default => 'hidden',
}
"
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)"
/>
@endif
<{{ $tag }}
@if ($tag === 'a')
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if (($keyBindings || $hasTooltip) && (! $hasFormProcessingLoadingIndicator))
x-data="{}"
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
@if ($hasFormProcessingLoadingIndicator)
x-data="{
form: null,
isProcessing: false,
processingMessage: null,
}"
x-init="
form = $el.closest('form')
form?.addEventListener('form-processing-started', (event) => {
isProcessing = true
processingMessage = event.detail.message
})
form?.addEventListener('form-processing-finished', () => {
isProcessing = false
})
"
x-bind:class="{ 'enabled:opacity-70 enabled:cursor-wait': isProcessing }"
@endif
{{
$attributes
->merge([
'disabled' => $disabled,
'form' => $formId,
'type' => $tag === 'button' ? $type : null,
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
'x-bind:disabled' => $hasFormProcessingLoadingIndicator ? 'isProcessing' : null,
], escape: false)
->class([$buttonClasses])
->style([$buttonStyles])
}}
>
@if ($iconPosition === IconPosition::Before)
@if ($icon)
<x-filament::icon
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'alias' => $iconAlias,
'icon' => $icon,
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : null,
])
)->class([$iconClasses])
"
/>
@endif
@if ($hasLoadingIndicator)
<x-filament::loading-indicator
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])
)->class([$iconClasses])
"
/>
@endif
@if ($hasFormProcessingLoadingIndicator)
<x-filament::loading-indicator
x-cloak="x-cloak"
x-show="isProcessing"
:class="$iconClasses"
/>
@endif
@endif
<span
@if ($hasFormProcessingLoadingIndicator)
x-show="! isProcessing"
@endif
class="{{ $labelClasses }}"
>
{{ $slot }}
</span>
@if ($hasFormProcessingLoadingIndicator)
<span
x-cloak
x-show="isProcessing"
x-text="processingMessage"
class="{{ $labelClasses }}"
></span>
@endif
@if ($iconPosition === IconPosition::After)
@if ($icon)
<x-filament::icon
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'alias' => $iconAlias,
'icon' => $icon,
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : null,
])
)->class([$iconClasses])
"
/>
@endif
@if ($hasLoadingIndicator)
<x-filament::loading-indicator
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])
)->class([$iconClasses])
"
/>
@endif
@if ($hasFormProcessingLoadingIndicator)
<x-filament::loading-indicator
x-cloak="x-cloak"
x-show="isProcessing"
:class="$iconClasses"
/>
@endif
@endif
@if (filled($badge))
<div class="{{ $badgeContainerClasses }}">
<x-filament::badge :color="$badgeColor" :size="$badgeSize">
{{ $badge }}
</x-filament::badge>
</div>
@endif
</{{ $tag }}>

View File

@@ -0,0 +1,3 @@
<x-filament::section>
{{ $slot }}
</x-filament::section>

View File

@@ -0,0 +1,71 @@
@php
use Filament\Support\Enums\IconSize;
@endphp
@props([
'color' => 'gray',
'icon' => null,
'iconSize' => IconSize::Medium,
'tag' => 'div',
])
<{{ $tag }}
{{
$attributes
->class([
'fi-dropdown-header flex w-full gap-2 p-3 text-sm',
match ($color) {
'gray' => null,
default => 'fi-color-custom',
},
// @deprecated `fi-dropdown-header-color-*` has been replaced by `fi-color-*` and `fi-color-custom`.
is_string($color) ? "fi-dropdown-header-color-{$color}" : null,
is_string($color) ? "fi-color-{$color}" : null,
])
}}
>
@if (filled($icon))
<x-filament::icon
:icon="$icon"
@class([
'fi-dropdown-header-icon',
match ($iconSize) {
IconSize::Small, 'sm' => 'h-4 w-4',
IconSize::Medium, 'md' => 'h-5 w-5',
IconSize::Large, 'lg' => 'h-6 w-6',
default => $iconSize,
},
match ($color) {
'gray' => 'text-gray-400 dark:text-gray-500',
default => 'text-custom-500 dark:text-custom-400',
},
])
@style([
\Filament\Support\get_color_css_variables(
$color,
shades: [400, 500],
alias: 'dropdown.header.icon',
) => $color !== 'gray',
])
/>
@endif
<span
@class([
'fi-dropdown-header-label flex-1 truncate text-start',
match ($color) {
'gray' => 'text-gray-700 dark:text-gray-200',
default => 'text-custom-600 dark:text-custom-400',
},
])
@style([
\Filament\Support\get_color_css_variables(
$color,
shades: [400, 600],
alias: 'dropdown.header.label',
) => $color !== 'gray',
])
>
{{ $slot }}
</span>
</{{ $tag }}>

View File

@@ -0,0 +1,87 @@
@props([
'availableHeight' => null,
'availableWidth' => null,
'flip' => true,
'maxHeight' => null,
'offset' => 8,
'placement' => null,
'shift' => false,
'size' => false,
'sizePadding' => 16,
'teleport' => false,
'trigger' => null,
'width' => null,
])
@php
use Filament\Support\Enums\MaxWidth;
$sizeConfig = collect([
'availableHeight' => $availableHeight,
'availableWidth' => $availableWidth,
'padding' => $sizePadding,
])->filter()->toJson();
@endphp
<div
x-data="{
toggle: function (event) {
$refs.panel.toggle(event)
},
open: function (event) {
$refs.panel.open(event)
},
close: function (event) {
$refs.panel.close(event)
},
}"
{{ $attributes->class(['fi-dropdown']) }}
>
<div
x-on:click="toggle"
{{ $trigger->attributes->class(['fi-dropdown-trigger flex cursor-pointer']) }}
>
{{ $trigger }}
</div>
@if (! \Filament\Support\is_slot_empty($slot))
<div
x-cloak
x-float{{ $placement ? ".placement.{$placement}" : '' }}{{ $size ? '.size' : '' }}{{ $flip ? '.flip' : '' }}{{ $shift ? '.shift' : '' }}{{ $teleport ? '.teleport' : '' }}{{ $offset ? '.offset' : '' }}="{ offset: {{ $offset }}, {{ $size ? ('size: ' . $sizeConfig) : '' }} }"
x-ref="panel"
x-transition:enter-start="opacity-0"
x-transition:leave-end="opacity-0"
@if ($attributes->has('wire:key'))
wire:ignore.self
wire:key="{{ $attributes->get('wire:key') }}.panel"
@endif
@class([
'fi-dropdown-panel absolute z-10 w-screen divide-y divide-gray-100 rounded-lg bg-white shadow-lg ring-1 ring-gray-950/5 transition dark:divide-white/5 dark:bg-gray-900 dark:ring-white/10',
match ($width) {
// These max width classes need to be `!important` otherwise they will be usurped by the Floating UI "size" middleware.
MaxWidth::ExtraSmall, 'xs' => '!max-w-xs',
MaxWidth::Small, 'sm' => '!max-w-sm',
MaxWidth::Medium, 'md' => '!max-w-md',
MaxWidth::Large, 'lg' => '!max-w-lg',
MaxWidth::ExtraLarge, 'xl' => '!max-w-xl',
MaxWidth::TwoExtraLarge, '2xl' => '!max-w-2xl',
MaxWidth::ThreeExtraLarge, '3xl' => '!max-w-3xl',
MaxWidth::FourExtraLarge, '4xl' => '!max-w-4xl',
MaxWidth::FiveExtraLarge, '5xl' => '!max-w-5xl',
MaxWidth::SixExtraLarge, '6xl' => '!max-w-6xl',
MaxWidth::SevenExtraLarge, '7xl' => '!max-w-7xl',
null => '!max-w-[14rem]',
default => $width,
},
'overflow-y-auto' => $maxHeight || $size,
])
@style([
"max-height: {$maxHeight}" => $maxHeight,
])
>
{{ $slot }}
</div>
@endif
</div>

View File

@@ -0,0 +1,3 @@
<div {{ $attributes->class(['fi-dropdown-list p-1']) }}>
{{ $slot }}
</div>

View File

@@ -0,0 +1,275 @@
@php
use Filament\Support\Enums\IconSize;
@endphp
@props([
'badge' => null,
'badgeColor' => null,
'badgeTooltip' => null,
'color' => 'gray',
'disabled' => false,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconColor' => null,
'iconSize' => IconSize::Medium,
'image' => null,
'keyBindings' => null,
'loadingIndicator' => true,
'spaMode' => null,
'tag' => 'button',
'target' => null,
'tooltip' => null,
])
@php
$buttonClasses = \Illuminate\Support\Arr::toCssClasses([
'fi-dropdown-list-item flex w-full items-center gap-2 whitespace-nowrap rounded-md p-2 text-sm transition-colors duration-75 outline-none disabled:pointer-events-none disabled:opacity-70',
'pointer-events-none opacity-70' => $disabled,
match ($color) {
'gray' => 'hover:bg-gray-50 focus-visible:bg-gray-50 dark:hover:bg-white/5 dark:focus-visible:bg-white/5',
default => 'fi-color-custom hover:bg-custom-50 focus-visible:bg-custom-50 dark:hover:bg-custom-400/10 dark:focus-visible:bg-custom-400/10',
},
// @deprecated `fi-dropdown-list-item-color-*` has been replaced by `fi-color-*` and `fi-color-custom`.
is_string($color) ? "fi-dropdown-list-item-color-{$color}" : null,
is_string($color) ? "fi-color-{$color}" : null,
]);
$buttonStyles = \Illuminate\Support\Arr::toCssStyles([
\Filament\Support\get_color_css_variables(
$color,
shades: [50, 400],
alias: 'dropdown.list.item',
) => $color !== 'gray',
]);
$iconColor ??= $color;
$iconClasses = \Illuminate\Support\Arr::toCssClasses([
'fi-dropdown-list-item-icon',
match ($iconSize) {
IconSize::Small, 'sm' => 'h-4 w-4',
IconSize::Medium, 'md' => 'h-5 w-5',
IconSize::Large, 'lg' => 'h-6 w-6',
default => $iconSize,
},
match ($iconColor) {
'gray' => 'text-gray-400 dark:text-gray-500',
default => 'text-custom-500 dark:text-custom-400',
},
]);
$iconStyles = \Illuminate\Support\Arr::toCssStyles([
\Filament\Support\get_color_css_variables(
$iconColor,
shades: [400, 500],
alias: 'dropdown.list.item.icon',
) => $iconColor !== 'gray',
]);
$imageClasses = 'fi-dropdown-list-item-image h-5 w-5 rounded-full bg-cover bg-center';
$labelClasses = \Illuminate\Support\Arr::toCssClasses([
'fi-dropdown-list-item-label flex-1 truncate text-start',
match ($color) {
'gray' => 'text-gray-700 dark:text-gray-200',
default => 'text-custom-600 dark:text-custom-400 ',
},
]);
$labelStyles = \Illuminate\Support\Arr::toCssStyles([
\Filament\Support\get_color_css_variables(
$color,
shades: [400, 600],
alias: 'dropdown.list.item.label',
) => $color !== 'gray',
]);
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasLoadingIndicator = filled($wireTarget);
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
@if ($tag === 'button')
<button
@if ($keyBindings || $hasTooltip)
x-data="{}"
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->merge([
'disabled' => $disabled,
'type' => 'button',
'wire:loading.attr' => 'disabled',
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : null,
], escape: false)
->class([$buttonClasses])
->style([$buttonStyles])
}}
>
@if ($icon)
<x-filament::icon
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'alias' => $iconAlias,
'icon' => $icon,
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : null,
])
)
->class([$iconClasses])
->style([$iconStyles])
"
/>
@endif
@if ($image)
<div
class="{{ $imageClasses }}"
style="background-image: url('{{ $image }}')"
></div>
@endif
@if ($hasLoadingIndicator)
<x-filament::loading-indicator
:attributes="
\Filament\Support\prepare_inherited_attributes(
new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])
)
->class([$iconClasses])
->style([$iconStyles])
"
/>
@endif
<span class="{{ $labelClasses }}" style="{{ $labelStyles }}">
{{ $slot }}
</span>
@if (filled($badge))
<x-filament::badge
:color="$badgeColor"
size="sm"
:tooltip="$badgeTooltip"
>
{{ $badge }}
</x-filament::badge>
@endif
</button>
@elseif ($tag === 'a')
<a
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@if ($keyBindings || $hasTooltip)
x-data="{}"
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->class([$buttonClasses])
->style([$buttonStyles])
}}
>
@if ($icon)
<x-filament::icon
:alias="$iconAlias"
:icon="$icon"
:class="$iconClasses"
:style="$iconStyles"
/>
@endif
@if ($image)
<div
class="{{ $imageClasses }}"
style="background-image: url('{{ $image }}')"
></div>
@endif
<span class="{{ $labelClasses }}" style="{{ $labelStyles }}">
{{ $slot }}
</span>
@if (filled($badge))
<x-filament::badge :color="$badgeColor" size="sm">
{{ $badge }}
</x-filament::badge>
@endif
</a>
@elseif ($tag === 'form')
<form
{{ $attributes->only(['action', 'class', 'method', 'wire:submit']) }}
>
@csrf
<button
@if ($keyBindings || $hasTooltip)
x-data="{}"
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
type="submit"
{{
$attributes
->except(['action', 'class', 'method', 'wire:submit'])
->class([$buttonClasses])
->style([$buttonStyles])
}}
>
@if ($icon)
<x-filament::icon
:alias="$iconAlias"
:icon="$icon"
:class="$iconClasses"
:style="$iconStyles"
/>
@endif
<span class="{{ $labelClasses }}" style="{{ $labelStyles }}">
{{ $slot }}
</span>
@if (filled($badge))
<x-filament::badge :color="$badgeColor" size="sm">
{{ $badge }}
</x-filament::badge>
@endif
</button>
</form>
@endif

View File

@@ -0,0 +1,25 @@
@props([
'label' => null,
'labelHidden' => false,
])
<fieldset
{{
$attributes->class([
'fi-fieldset rounded-xl border border-gray-200 p-6 dark:border-white/10',
])
}}
>
@if (filled($label))
<legend
@class([
'-ms-2 px-2 text-sm font-medium leading-6 text-gray-950 dark:text-white',
'sr-only' => $labelHidden,
])
>
{{ $label }}
</legend>
@endif
{{ $slot }}
</fieldset>

View File

@@ -0,0 +1,62 @@
@props([
'default' => 1,
'sm' => null,
'md' => null,
'lg' => null,
'xl' => null,
'twoXl' => null,
'defaultStart' => null,
'smStart' => null,
'mdStart' => null,
'lgStart' => null,
'xlStart' => null,
'twoXlStart' => null,
'hidden' => false,
])
@php
$getSpanValue = function ($span): string {
if ($span === 'full') {
return '1 / -1';
}
return "span {$span} / span {$span}";
};
@endphp
<div
{{
$attributes
->class([
'hidden' => $hidden || $default === 'hidden',
'col-[--col-span-default]' => $default && (! $hidden),
'sm:col-[--col-span-sm]' => $sm && (! $hidden),
'md:col-[--col-span-md]' => $md && (! $hidden),
'lg:col-[--col-span-lg]' => $lg && (! $hidden),
'xl:col-[--col-span-xl]' => $xl && (! $hidden),
'2xl:col-[--col-span-2xl]' => $twoXl && (! $hidden),
'col-start-[--col-start-default]' => $defaultStart && (! $hidden),
'sm:col-start-[--col-start-sm]' => $smStart && (! $hidden),
'md:col-start-[--col-start-md]' => $mdStart && (! $hidden),
'lg:col-start-[--col-start-lg]' => $lgStart && (! $hidden),
'xl:col-start-[--col-start-xl]' => $xlStart && (! $hidden),
'2xl:col-start-[--col-start-2xl]' => $twoXlStart && (! $hidden),
])
->style([
"--col-span-default: {$getSpanValue($default)}" => $default,
"--col-span-sm: {$getSpanValue($sm)}" => $sm,
"--col-span-md: {$getSpanValue($md)}" => $md,
"--col-span-lg: {$getSpanValue($lg)}" => $lg,
"--col-span-xl: {$getSpanValue($xl)}" => $xl,
"--col-span-2xl: {$getSpanValue($twoXl)}" => $twoXl,
"--col-start-default: {$defaultStart}" => $defaultStart,
"--col-start-sm: {$smStart}" => $smStart,
"--col-start-md: {$mdStart}" => $mdStart,
"--col-start-lg: {$lgStart}" => $lgStart,
"--col-start-xl: {$xlStart}" => $xlStart,
"--col-start-2xl: {$twoXlStart}" => $twoXlStart,
])
}}
>
{{ $slot }}
</div>

Some files were not shown because too many files have changed in this diff Show More