Schema, model, Filament, cron, and visibility-semantics foundations required by the RouteForge change. Four phases delivered as one coherent change. Verified against four spec files (flight-bundles, flight-time-storage, subfleet-capability, flight-visibility). Phase 1.1 \xe2\x80\x94 Flight time columns - flights.departure_time, flights.arrival_time TIME NULL - Flight model accessors (Hi-format) + mutators (FlightTimeParser) - FlightTimeParser supports 9 formats + Z/L/tz suffix stripping - Migration backfills inline via chunked raw DB::table->update() - Legacy dpt_time/arr_time VARCHAR columns preserved for one release Phase 1.2 \xe2\x80\x94 Subfleet capability columns - subfleets.cruise_speed, max_range_nm, route_types (CSV VARCHAR(64)) - FlightTypesCast splits/sorts/dedupes/logs-on-invalid - routeforge defaults in config/phpvms.php - SubfleetForm Operational Capability section Phase 1.3 \xe2\x80\x94 Flight Bundles - flight_bundles table + flights.bundle_id NOT NULL FK - Default bundle seeded inline; existing flights backfilled - FlightBundle model + factory + BundleObserver (queued recompute) - FlightBundleResource as sole Flights nav entry (slug=flights, icon=OutlinedMap, sort=2) - Nested FlightResource under FlightBundleResource (slug=flight, parentResource, create+edit only, no nav entry) - FlightsRelationManager with relatedResource for full-page row actions - FlightForm: bundle selector removed (route-bound), date inputs hidden when parent bundle owns dates, XSS-safe placeholder link - Date columns stored as TIMESTAMP UTC, UI converts to local tz - Soft-deleting a bundle leaves children non-deleted; visibility recompute sets visible=false (no cascade delete) - Spatie Shield permissions: flight_bundle.* seeded Phase 1.4 \xe2\x80\x94 Visibility semantics - flights.active renamed to flights.enabled (admin source of truth) - flights.visible is cron-managed combined state - SetActiveFlights cron deleted; SetVisibleFlights cron added - Two-pass bulk SQL UPDATE scoped by bundle, chunks of 500 - RecomputeBundleVisibility queued job dispatched on bundle save/restore - Flight::scopeVisible added; scopeActive retained as plain alias - Pilot-facing read sites use ->visible() (AirportController fix) - FlightResource JSON + FlightExporter CSV expose both enabled+active - Four-state status badge (Disabled / Disabled by Bundle / Enabled Out of Window / Enabled & In Window) replaces Visible toggle - 5 visibility indexes added Verification - 469 Pest tests passed (2058 assertions) - phpstan level 5 clean (646 files) - pint --test clean - rector --dry-run clean - All four spec files PASS (28 requirements + 36 scenarios verified by kimi-spec-reviewer) Migration path documented in docs/UPGRADING.md and openspec/changes/ schema-modernization-for-routeforge/.
124 lines
4.3 KiB
PHP
124 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Resources\FlightBundles\Resources\Flight\Tables;
|
|
|
|
use App\Models\Airport;
|
|
use App\Models\Flight;
|
|
use Filament\Actions\BulkActionGroup;
|
|
use Filament\Actions\DeleteAction;
|
|
use Filament\Actions\DeleteBulkAction;
|
|
use Filament\Actions\EditAction;
|
|
use Filament\Actions\ForceDeleteAction;
|
|
use Filament\Actions\ForceDeleteBulkAction;
|
|
use Filament\Actions\RestoreAction;
|
|
use Filament\Actions\RestoreBulkAction;
|
|
use Filament\Tables\Columns\IconColumn;
|
|
use Filament\Tables\Columns\TextColumn;
|
|
use Filament\Tables\Filters\SelectFilter;
|
|
use Filament\Tables\Filters\TrashedFilter;
|
|
use Filament\Tables\Table;
|
|
|
|
class FlightsTable
|
|
{
|
|
public static function configure(Table $table): Table
|
|
{
|
|
|
|
return $table
|
|
->columns([
|
|
TextColumn::make('ident')
|
|
->label(trans_choice('common.flight', 1).' #')
|
|
->searchable(['flight_number'])
|
|
->sortable(['airline_id', 'flight_number']),
|
|
|
|
TextColumn::make('dpt_airport_id')
|
|
->label(__('flights.dep'))
|
|
->searchable()
|
|
->sortable(),
|
|
|
|
TextColumn::make('arr_airport_id')
|
|
->label(__('flights.arr'))
|
|
->searchable()
|
|
->sortable(),
|
|
|
|
TextColumn::make('dpt_time')
|
|
->label(__('flights.departuretime'))
|
|
->sortable()
|
|
->toggleable(),
|
|
|
|
TextColumn::make('arr_time')
|
|
->label(__('flights.arrivaltime'))
|
|
->sortable()
|
|
->toggleable(),
|
|
|
|
TextColumn::make('notes')
|
|
->label(__('common.notes'))
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
|
|
IconColumn::make('enabled')
|
|
->label(__('common.enabled'))
|
|
->boolean()
|
|
->sortable(),
|
|
|
|
TextColumn::make('status_badge')
|
|
->label(__('common.status'))
|
|
->badge()
|
|
->state(function (Flight $record): string {
|
|
if (!$record->enabled) {
|
|
return __('filament.flights.status.disabled');
|
|
}
|
|
|
|
if ($record->visible) {
|
|
return __('filament.flights.status.enabled_in_window');
|
|
}
|
|
|
|
return __('filament.flights.status.enabled_out_of_window');
|
|
})
|
|
->color(function (Flight $record): string {
|
|
if (!$record->enabled) {
|
|
return 'danger';
|
|
}
|
|
|
|
return $record->visible ? 'success' : 'warning';
|
|
}),
|
|
])
|
|
->filters([
|
|
TrashedFilter::make(),
|
|
|
|
SelectFilter::make('airline')
|
|
->relationship('airline', 'name')
|
|
->label(__('common.airline'))
|
|
->searchable()
|
|
->preload(),
|
|
|
|
SelectFilter::make('dpt_airport')
|
|
->label(__('airports.departure'))
|
|
->relationship('dpt_airport', 'icao')
|
|
->getOptionLabelFromRecordUsing(fn (Airport $record): string => $record->icao.' - '.$record->name)
|
|
->searchable()
|
|
->preload(),
|
|
|
|
SelectFilter::make('arr_airport')
|
|
->label(__('airports.arrival'))
|
|
->relationship('arr_airport', 'icao')
|
|
->getOptionLabelFromRecordUsing(fn (Airport $record): string => $record->icao.' - '.$record->name)
|
|
->searchable()
|
|
->preload(),
|
|
])
|
|
->recordActions([
|
|
EditAction::make(),
|
|
DeleteAction::make(),
|
|
ForceDeleteAction::make(),
|
|
RestoreAction::make(),
|
|
])
|
|
->toolbarActions([
|
|
BulkActionGroup::make([
|
|
DeleteBulkAction::make(),
|
|
ForceDeleteBulkAction::make(),
|
|
RestoreBulkAction::make(),
|
|
]),
|
|
])
|
|
->emptyStateActions([
|
|
]);
|
|
}
|
|
}
|