diff --git a/app/Filament/Exports/ItemExporter.php b/app/Filament/Exports/ItemExporter.php new file mode 100644 index 0000000..e08260b --- /dev/null +++ b/app/Filament/Exports/ItemExporter.php @@ -0,0 +1,38 @@ +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; + } +} diff --git a/app/Filament/Imports/ItemImporter.php b/app/Filament/Imports/ItemImporter.php new file mode 100644 index 0000000..849ee56 --- /dev/null +++ b/app/Filament/Imports/ItemImporter.php @@ -0,0 +1,56 @@ +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; + } +} diff --git a/app/Filament/Imports/ProductionQuantityImporter.php b/app/Filament/Imports/ProductionQuantityImporter.php new file mode 100644 index 0000000..c2828db --- /dev/null +++ b/app/Filament/Imports/ProductionQuantityImporter.php @@ -0,0 +1,91 @@ +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; + } +} diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php new file mode 100644 index 0000000..20604ae --- /dev/null +++ b/app/Filament/Pages/Dashboard.php @@ -0,0 +1,26 @@ +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'), + ]); + } +} diff --git a/app/Filament/Resources/BlockResource.php b/app/Filament/Resources/BlockResource.php new file mode 100644 index 0000000..b37030f --- /dev/null +++ b/app/Filament/Resources/BlockResource.php @@ -0,0 +1,102 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/BlockResource/Pages/CreateBlock.php b/app/Filament/Resources/BlockResource/Pages/CreateBlock.php new file mode 100644 index 0000000..052c495 --- /dev/null +++ b/app/Filament/Resources/BlockResource/Pages/CreateBlock.php @@ -0,0 +1,12 @@ +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(), + ]), + ]); + } +} diff --git a/app/Filament/Resources/CompanyResource.php b/app/Filament/Resources/CompanyResource.php index 0f9faaa..7830c2d 100644 --- a/app/Filament/Resources/CompanyResource.php +++ b/app/Filament/Resources/CompanyResource.php @@ -17,7 +17,9 @@ class CompanyResource extends Resource { 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 { @@ -25,6 +27,7 @@ class CompanyResource extends Resource ->schema([ Forms\Components\TextInput::make('name') ->required() + ->unique() ->columnSpanFull(), ]); } @@ -37,7 +40,6 @@ class CompanyResource extends Resource ->label('ID') ->numeric() ->sortable(), - Tables\Columns\TextColumn::make('name') ->sortable(), Tables\Columns\TextColumn::make('created_at') @@ -45,10 +47,12 @@ class CompanyResource extends Resource ->sortable(), Tables\Columns\TextColumn::make('updated_at') ->dateTime() - ->sortable(), + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('deleted_at') ->dateTime() - ->sortable(), + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ Tables\Filters\TrashedFilter::make(), diff --git a/app/Filament/Resources/ItemResource.php b/app/Filament/Resources/ItemResource.php new file mode 100644 index 0000000..d55e80f --- /dev/null +++ b/app/Filament/Resources/ItemResource.php @@ -0,0 +1,120 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/ItemResource/Pages/CreateItem.php b/app/Filament/Resources/ItemResource/Pages/CreateItem.php new file mode 100644 index 0000000..40e94d7 --- /dev/null +++ b/app/Filament/Resources/ItemResource/Pages/CreateItem.php @@ -0,0 +1,12 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/LineResource/Pages/CreateLine.php b/app/Filament/Resources/LineResource/Pages/CreateLine.php new file mode 100644 index 0000000..8cb7a10 --- /dev/null +++ b/app/Filament/Resources/LineResource/Pages/CreateLine.php @@ -0,0 +1,12 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/LineStopResource/Pages/CreateLineStop.php b/app/Filament/Resources/LineStopResource/Pages/CreateLineStop.php new file mode 100644 index 0000000..3e77035 --- /dev/null +++ b/app/Filament/Resources/LineStopResource/Pages/CreateLineStop.php @@ -0,0 +1,12 @@ +schema([ Forms\Components\TextInput::make('code') ->required() - ->unique() - ->minValue(1000) - ->numeric(), + ->unique(ignoreRecord: true) + ->numeric() + ->minValue(1000), Forms\Components\Select::make('company_id') ->relationship('company', 'name') ->required(), Forms\Components\TextInput::make('name') ->required() + ->unique(ignoreRecord: true) ->columnSpanFull(), Forms\Components\Textarea::make('address') ->required() + ->unique(ignoreRecord: true) ->columnSpanFull(), ]) ->columns(2), @@ -55,8 +59,9 @@ class PlantResource extends Resource Tables\Columns\TextColumn::make('code') ->numeric() ->sortable(), + Tables\Columns\TextColumn::make('name') + ->sortable(), Tables\Columns\TextColumn::make('company.name') - ->numeric() ->sortable(), Tables\Columns\TextColumn::make('created_at') ->dateTime() diff --git a/app/Filament/Resources/ProductionLineStopResource.php b/app/Filament/Resources/ProductionLineStopResource.php new file mode 100644 index 0000000..09316b6 --- /dev/null +++ b/app/Filament/Resources/ProductionLineStopResource.php @@ -0,0 +1,144 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/ProductionLineStopResource/Pages/CreateProductionLineStop.php b/app/Filament/Resources/ProductionLineStopResource/Pages/CreateProductionLineStop.php new file mode 100644 index 0000000..37ca32d --- /dev/null +++ b/app/Filament/Resources/ProductionLineStopResource/Pages/CreateProductionLineStop.php @@ -0,0 +1,12 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/ProductionPlanResource/Pages/CreateProductionPlan.php b/app/Filament/Resources/ProductionPlanResource/Pages/CreateProductionPlan.php new file mode 100644 index 0000000..26a905d --- /dev/null +++ b/app/Filament/Resources/ProductionPlanResource/Pages/CreateProductionPlan.php @@ -0,0 +1,12 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/ProductionQuantityResource/Pages/CreateProductionQuantity.php b/app/Filament/Resources/ProductionQuantityResource/Pages/CreateProductionQuantity.php new file mode 100644 index 0000000..0ad7efb --- /dev/null +++ b/app/Filament/Resources/ProductionQuantityResource/Pages/CreateProductionQuantity.php @@ -0,0 +1,12 @@ +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, + ]); + } +} diff --git a/app/Filament/Resources/ShiftResource/Pages/CreateShift.php b/app/Filament/Resources/ShiftResource/Pages/CreateShift.php new file mode 100644 index 0000000..8aa2109 --- /dev/null +++ b/app/Filament/Resources/ShiftResource/Pages/CreateShift.php @@ -0,0 +1,12 @@ +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', + ]; + } + +} diff --git a/app/Models/Block.php b/app/Models/Block.php new file mode 100644 index 0000000..72287b3 --- /dev/null +++ b/app/Models/Block.php @@ -0,0 +1,33 @@ +belongsTo(Plant::class); + } + + public function shifts(): HasMany + { + return $this->hasMany(Shift::class); + } + + public function lines(): HasMany + { + return $this->hasMany(Line::class); + } +} diff --git a/app/Models/Item.php b/app/Models/Item.php new file mode 100644 index 0000000..dba63d8 --- /dev/null +++ b/app/Models/Item.php @@ -0,0 +1,17 @@ +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); + } +} diff --git a/app/Models/LineStop.php b/app/Models/LineStop.php new file mode 100644 index 0000000..41a5793 --- /dev/null +++ b/app/Models/LineStop.php @@ -0,0 +1,36 @@ +belongsTo(Plant::class); + } + + public function block(): BelongsTo + { + return $this->belongsTo(Block::class); + } + + public function shift(): BelongsTo + { + return $this->belongsTo(Shift::class); + } +} diff --git a/app/Models/Plant.php b/app/Models/Plant.php index 3f053b3..8d42542 100644 --- a/app/Models/Plant.php +++ b/app/Models/Plant.php @@ -4,6 +4,7 @@ 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 Plant extends Model @@ -21,4 +22,9 @@ class Plant extends Model { return $this->belongsTo(Company::class); } + + public function blocks(): HasMany + { + return $this->hasMany(Block::class); + } } diff --git a/app/Models/ProductionLineStop.php b/app/Models/ProductionLineStop.php new file mode 100644 index 0000000..653bd85 --- /dev/null +++ b/app/Models/ProductionLineStop.php @@ -0,0 +1,50 @@ +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); + } +} diff --git a/app/Models/ProductionPlan.php b/app/Models/ProductionPlan.php new file mode 100644 index 0000000..4942dd4 --- /dev/null +++ b/app/Models/ProductionPlan.php @@ -0,0 +1,35 @@ +belongsTo(Plant::class); + } + + public function shift(): BelongsTo + { + return $this->belongsTo(Shift::class); + } + + public function line(): BelongsTo + { + return $this->belongsTo(Line::class); + } +} diff --git a/app/Models/ProductionQuantity.php b/app/Models/ProductionQuantity.php new file mode 100644 index 0000000..12e9c69 --- /dev/null +++ b/app/Models/ProductionQuantity.php @@ -0,0 +1,43 @@ +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); + } +} diff --git a/app/Models/Shift.php b/app/Models/Shift.php new file mode 100644 index 0000000..5012e68 --- /dev/null +++ b/app/Models/Shift.php @@ -0,0 +1,36 @@ +belongsTo(Plant::class); + // } + + public function block(): BelongsTo + { + return $this->belongsTo(Block::class); + } + + public function plant(): BelongsTo + { + return $this->belongsTo(Plant::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 749c7b7..ff5888a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,11 +6,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { /** @use HasFactory<\Database\Factories\UserFactory> */ - use HasFactory, Notifiable; + use HasFactory, HasRoles, Notifiable; /** * The attributes that are mass assignable. diff --git a/app/Policies/BlockPolicy.php b/app/Policies/BlockPolicy.php new file mode 100644 index 0000000..332e2f9 --- /dev/null +++ b/app/Policies/BlockPolicy.php @@ -0,0 +1,65 @@ +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; + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..e5970ac 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use Illuminate\Support\Facades\Gate; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -19,6 +20,8 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - // + Gate::before(function ($user, $ability) { + return $user->hasRole('Super Admin') ? true : null; + }); } } diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 6694332..a474fea 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -2,6 +2,7 @@ namespace App\Providers\Filament; +use Althinect\FilamentSpatieRolesPermissions\FilamentSpatieRolesPermissionsPlugin; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\AuthenticateSession; use Filament\Http\Middleware\DisableBladeIconComponents; @@ -24,22 +25,24 @@ class AdminPanelProvider extends PanelProvider { return $panel ->default() + ->id('admin') ->path('admin') ->login() + ->favicon(asset('/assets/crilogo1.png')) ->colors([ 'primary' => Color::Amber, ]) ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') ->pages([ - Pages\Dashboard::class, + ]) ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets') - ->widgets([ - Widgets\AccountWidget::class, - Widgets\FilamentInfoWidget::class, - ]) + // ->widgets([ + // Widgets\AccountWidget::class, + // Widgets\FilamentInfoWidget::class, + // ]) ->middleware([ EncryptCookies::class, AddQueuedCookiesToResponse::class, @@ -53,6 +56,8 @@ class AdminPanelProvider extends PanelProvider ]) ->authMiddleware([ Authenticate::class, - ]); + ]) + ->databaseNotifications() + ->plugin(FilamentSpatieRolesPermissionsPlugin::make()); } } diff --git a/composer.json b/composer.json index 9f164e8..5832820 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "license": "MIT", "require": { "php": "^8.2", + "althinect/filament-spatie-roles-permissions": "^2.3", "filament/filament": "^3.3", "laravel/framework": "^11.31", "laravel/tinker": "^2.9" diff --git a/composer.lock b/composer.lock index 5f2b19b..f11b24d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,71 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c2247a5e7b193701c7a41ae798179d8e", + "content-hash": "292ea7e3ed35e47bcbea3972cfa9bb78", "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", "version": "1.2.29", @@ -4885,6 +4948,89 @@ ], "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", "version": "v7.2.0", diff --git a/config/filament-spatie-roles-permissions.php b/config/filament-spatie-roles-permissions.php new file mode 100644 index 0000000..82bf9c6 --- /dev/null +++ b/config/filament-spatie-roles-permissions.php @@ -0,0 +1,218 @@ + [ + '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', + ], +]; diff --git a/config/filament.php b/config/filament.php new file mode 100644 index 0000000..65b4bf0 --- /dev/null +++ b/config/filament.php @@ -0,0 +1,89 @@ + [ + + // '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', + +]; diff --git a/config/permission.php b/config/permission.php new file mode 100644 index 0000000..8e84e9d --- /dev/null +++ b/config/permission.php @@ -0,0 +1,202 @@ + [ + + /* + * 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', + ], +]; diff --git a/database/migrations/2025_03_19_161954_create_companies_table.php b/database/migrations/2025_03_19_161954_create_companies_table.php index d4a0e15..749561a 100644 --- a/database/migrations/2025_03_19_161954_create_companies_table.php +++ b/database/migrations/2025_03_19_161954_create_companies_table.php @@ -13,7 +13,7 @@ return new class extends Migration $sql = <<<'SQL' CREATE TABLE companies ( 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(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), diff --git a/database/migrations/2025_03_19_171555_create_plants_table.php b/database/migrations/2025_03_19_171555_create_plants_table.php index bf03ddd..6916201 100644 --- a/database/migrations/2025_03_19_171555_create_plants_table.php +++ b/database/migrations/2025_03_19_171555_create_plants_table.php @@ -15,10 +15,10 @@ return new class extends Migration id BIGINT GENERATED always AS IDENTITY PRIMARY KEY, 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 - address TEXT NOT NULL, + name CITEXT NOT NULL UNIQUE, -- CITEXT use extension + address CITEXT NOT NULL, created_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) ); - SQL; DB::statement($sql); diff --git a/database/migrations/2025_03_20_115918_create_blocks_table.php b/database/migrations/2025_03_20_115918_create_blocks_table.php new file mode 100644 index 0000000..f161609 --- /dev/null +++ b/database/migrations/2025_03_20_115918_create_blocks_table.php @@ -0,0 +1,39 @@ += 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'); + } +}; diff --git a/database/migrations/2025_03_21_113453_add_status_column_to_shifts_table.php b/database/migrations/2025_03_21_113453_add_status_column_to_shifts_table.php new file mode 100644 index 0000000..5ef1715 --- /dev/null +++ b/database/migrations/2025_03_21_113453_add_status_column_to_shifts_table.php @@ -0,0 +1,29 @@ +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'); + } +}; diff --git a/database/migrations/2025_03_21_115025_create_imports_table.php b/database/migrations/2025_03_21_115025_create_imports_table.php new file mode 100644 index 0000000..100b7d9 --- /dev/null +++ b/database/migrations/2025_03_21_115025_create_imports_table.php @@ -0,0 +1,35 @@ +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'); + } +}; diff --git a/database/migrations/2025_03_21_115026_create_exports_table.php b/database/migrations/2025_03_21_115026_create_exports_table.php new file mode 100644 index 0000000..a4aab11 --- /dev/null +++ b/database/migrations/2025_03_21_115026_create_exports_table.php @@ -0,0 +1,35 @@ +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'); + } +}; diff --git a/database/migrations/2025_03_21_115027_create_failed_import_rows_table.php b/database/migrations/2025_03_21_115027_create_failed_import_rows_table.php new file mode 100644 index 0000000..260507e --- /dev/null +++ b/database/migrations/2025_03_21_115027_create_failed_import_rows_table.php @@ -0,0 +1,30 @@ +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'); + } +}; diff --git a/database/migrations/2025_03_21_124542_create_permission_tables.php b/database/migrations/2025_03_21_124542_create_permission_tables.php new file mode 100644 index 0000000..70a120f --- /dev/null +++ b/database/migrations/2025_03_21_124542_create_permission_tables.php @@ -0,0 +1,140 @@ +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']); + } +}; diff --git a/database/migrations/2025_03_22_184847_create_line_stops_table.php b/database/migrations/2025_03_22_184847_create_line_stops_table.php new file mode 100644 index 0000000..01e5348 --- /dev/null +++ b/database/migrations/2025_03_22_184847_create_line_stops_table.php @@ -0,0 +1,46 @@ + 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'); + } +}; diff --git a/database/migrations/2025_03_23_163259_create_production_line_stops_table.php b/database/migrations/2025_03_23_163259_create_production_line_stops_table.php new file mode 100644 index 0000000..efbba6e --- /dev/null +++ b/database/migrations/2025_03_23_163259_create_production_line_stops_table.php @@ -0,0 +1,52 @@ +create(); - - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', - ]); + $this->call(RoleSeeder::class); + $this->call(UserSeeder::class); } } diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..e50ea86 --- /dev/null +++ b/database/seeders/RoleSeeder.php @@ -0,0 +1,20 @@ + 'Super Admin', + 'guard_name' => 'web', + ]); + } +} diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 0000000..c2fa2b4 --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,33 @@ + '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(); + } +} diff --git a/public/assets b/public/assets new file mode 120000 index 0000000..ec9d244 --- /dev/null +++ b/public/assets @@ -0,0 +1 @@ +/home/iot-dev/projects/pds/storage/app/public \ No newline at end of file diff --git a/resources/views/vendor/filament/assets.blade.php b/resources/views/vendor/filament/assets.blade.php new file mode 100644 index 0000000..1cf3bde --- /dev/null +++ b/resources/views/vendor/filament/assets.blade.php @@ -0,0 +1,17 @@ +@if (isset($data)) + +@endif + +@foreach ($assets as $asset) + @if (! $asset->isLoadedOnRequest()) + {{ $asset->getHtml() }} + @endif +@endforeach + + diff --git a/resources/views/vendor/filament/components/actions.blade.php b/resources/views/vendor/filament/components/actions.blade.php new file mode 100644 index 0000000..607d546 --- /dev/null +++ b/resources/views/vendor/filament/components/actions.blade.php @@ -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) +
class(['fi-modal-description text-sm text-gray-500 dark:text-gray-400']) }} +> + {{ $slot }} +
diff --git a/resources/views/vendor/filament/components/modal/heading.blade.php b/resources/views/vendor/filament/components/modal/heading.blade.php new file mode 100644 index 0000000..be4fadc --- /dev/null +++ b/resources/views/vendor/filament/components/modal/heading.blade.php @@ -0,0 +1,5 @@ +class(['fi-section-header-description overflow-hidden break-words text-sm text-gray-500 dark:text-gray-400']) }} +> + {{ $slot }} +
diff --git a/resources/views/vendor/filament/components/section/heading.blade.php b/resources/views/vendor/filament/components/section/heading.blade.php new file mode 100644 index 0000000..d0b550c --- /dev/null +++ b/resources/views/vendor/filament/components/section/heading.blade.php @@ -0,0 +1,5 @@ +