Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions app/Filament/Resources/SmrAreaResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php

namespace App\Filament\Resources;

use App\Filament\Helpers\HasCoordinates;
use App\Filament\Helpers\SelectOptions;
use App\Filament\Resources\SmrAreaResource\Pages;
use App\Models\SmrArea;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables\Table;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App;

class SmrAreaResource extends Resource
{
use TranslatesStrings;
use HasCoordinates;

protected static ?string $model = SmrArea::class;
protected static ?string $modelLabel = 'SMR Area';
protected static ?string $navigationGroup = 'Airfield';
protected static ?string $navigationIcon = 'heroicon-o-exclamation-triangle';
protected static ?string $navigationLabel = 'SMR Areas';
protected static ?string $pluralModelLabel = 'SMR Areas';

public static function form(Form $form): Form
{
return $form
->schema([
Select::make('airfield_id')
->label(self::translateFormPath('airfield.label'))
->helperText(self::translateFormPath('airfield.helper'))
->options(SelectOptions::airfields())
->searchable(!App::runningUnitTests())
->required(),
TextInput::make('name')
->label(self::translateFormPath('name.label'))
->helperText(self::translateFormPath('name.helper'))
->minLength(1)
->maxLength(255),
TextInput::make('source')
->label(self::translateFormPath('source.label'))
->helperText(self::translateFormPath('source.helper'))
->minLength(1)
->maxLength(255),
Textarea::make('coordinates')
->label(self::translateFormPath('coordinates.label'))
->helperText(self::translateFormPath('coordinates.helper'))
->rows(5)
->required()
// relatively lax validation; a stricter pattern is somewhat unnecessary
->regex('/^(COORD(:[NESW][\d\.]{13}){2}\n*){3,}$/'),
DateTimePicker::make('start_date')
->label(self::translateFormPath('start_date.label'))
->helperText(self::translateFormPath('start_date.helper')),
DateTimePicker::make('end_date')
->label(self::translateFormPath('end_date.label'))
->helperText(self::translateFormPath('end_date.helper'))
->after('start_date'),
]);
}

public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('airfield.code')
->label(self::translateTablePath('columns.airfield'))
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('name')
->label(self::translateTablePath('columns.name'))
->searchable(),
Tables\Columns\TextColumn::make('source')
->label(self::translateTablePath('columns.source'))
->searchable(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->filters([
Tables\Filters\Filter::make('expired')
->toggle()
->label(self::translateFilterPath('expired'))
->query(fn (Builder $query) => $query->expired()),
Tables\Filters\TernaryFilter::make('activation')
->label(self::translateFilterPath('activation.label'))
->trueLabel(self::translateFilterPath('activation.true'))
->falseLabel(self::translateFilterPath('activation.false'))
->queries(
true: fn (Builder $query) => $query->active(),
false: fn (Builder $query) => $query->whereNot->active(),
blank: fn (Builder $query) => $query,
),
]);
}

public static function getPages(): array
{
return [
'index' => Pages\ListSmrAreas::route('/'),
'create' => Pages\CreateSmrArea::route('/create'),
'view' => Pages\ViewSmrArea::route('/{record}'),
'edit' => Pages\EditSmrArea::route('/{record}/edit'),
];
}

protected static function translationPathRoot(): string
{
return 'smr_areas';
}
}
11 changes: 11 additions & 0 deletions app/Filament/Resources/SmrAreaResource/Pages/CreateSmrArea.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Filament\Resources\SmrAreaResource\Pages;

use App\Filament\Resources\SmrAreaResource;
use Filament\Resources\Pages\CreateRecord;

class CreateSmrArea extends CreateRecord
{
protected static string $resource = SmrAreaResource::class;
}
19 changes: 19 additions & 0 deletions app/Filament/Resources/SmrAreaResource/Pages/EditSmrArea.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace App\Filament\Resources\SmrAreaResource\Pages;

use App\Filament\Resources\SmrAreaResource;
use Filament\Pages\Actions;
use Filament\Resources\Pages\EditRecord;

class EditSmrArea extends EditRecord
{
protected static string $resource = SmrAreaResource::class;

protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}
21 changes: 21 additions & 0 deletions app/Filament/Resources/SmrAreaResource/Pages/ListSmrAreas.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace App\Filament\Resources\SmrAreaResource\Pages;

use App\Filament\Resources\Pages\LimitsTableRecordListingOptions;
use App\Filament\Resources\SmrAreaResource;
use Filament\Pages\Actions;
use Filament\Resources\Pages\ListRecords;

class ListSmrAreas extends ListRecords
{
use LimitsTableRecordListingOptions;
protected static string $resource = SmrAreaResource::class;

protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}
19 changes: 19 additions & 0 deletions app/Filament/Resources/SmrAreaResource/Pages/ViewSmrArea.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace App\Filament\Resources\SmrAreaResource\Pages;

use App\Filament\Resources\SmrAreaResource;
use Filament\Pages\Actions;
use Filament\Resources\Pages\ViewRecord;

class ViewSmrArea extends ViewRecord
{
protected static string $resource = SmrAreaResource::class;

protected function getHeaderActions(): array
{
return [
Actions\EditAction::make(),
];
}
}
20 changes: 20 additions & 0 deletions app/Http/Controllers/SmrAreaController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace App\Http\Controllers;

use App\Models\SmrArea;
use Illuminate\Http\Response;

class SmrAreaController extends Controller
{
public function getFormattedSmrAreas(): Response
{
return response(
// backwards-compatible format for vSMR: sline-format coordinates on
// each line, with polygons separated by at least one blank line
SmrArea::active()->pluck("coordinates")->join("\n\n"),
200,
["Content-Type" => "text/plain"],
);
}
}
50 changes: 50 additions & 0 deletions app/Models/SmrArea.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Models;

use App\Models\Airfield\Airfield;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class SmrArea extends Model
{
public $table = 'smr_area';

protected $fillable = [
'airfield_id',
'name',
'source',
'coordinates',
'start_date',
'end_date',
'created_at',
'updated_at',
];

protected $hidden = [
'created_at',
'updated_at',
];

public function airfield(): BelongsTo
{
return $this->belongsTo(Airfield::class);
}

public function scopeActive(Builder $query): Builder
{
return $query
->where(fn (Builder $query) => $query
->where('start_date', '<', now())
->orWhereNull('start_date'))
->where(fn (Builder $query) => $query
->where('end_date', '>', now())
->orWhereNull('end_date'));
}

public function scopeExpired(Builder $query): Builder
{
return $query->where('end_date', '<', now());
}
}
2 changes: 2 additions & 0 deletions app/Providers/AuthServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use App\Models\Plugin\PluginLog;
use App\Models\Runway\Runway;
use App\Models\Sid;
use App\Models\SmrArea;
use App\Models\Squawk\AirfieldPairing\AirfieldPairingSquawkRange;
use App\Models\Squawk\Ccams\CcamsSquawkRange;
use App\Models\Squawk\Orcam\OrcamSquawkRange;
Expand Down Expand Up @@ -79,6 +80,7 @@ class AuthServiceProvider extends ServiceProvider
Prenote::class => DefaultFilamentPolicy::class,
Runway::class => DefaultFilamentPolicy::class,
Sid::class => DefaultFilamentPolicy::class,
SmrArea::class => OperationsContributorPolicy::class,
Stand::class => OperationsContributorPolicy::class,
Terminal::class => OperationsContributorPolicy::class,
UnitConspicuitySquawkCode::class => DefaultFilamentPolicy::class,
Expand Down
37 changes: 37 additions & 0 deletions database/migrations/2025_04_30_220010_create_smr_area_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?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('smr_area', function (Blueprint $table) {
$table->id()->primary();
$table->unsignedInteger('airfield_id');
$table->string('name')->nullable();
$table->string('source')->nullable();
$table->text('coordinates');
$table->dateTime('start_date')->nullable();
$table->dateTime('end_date')->nullable();
$table->timestamps();

$table->foreign('airfield_id')
->references('id')
->on('airfield')
->cascadeOnDelete();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('smr_area');
}
};
3 changes: 3 additions & 0 deletions database/seeds/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ class DatabaseSeeder extends Seeder
IntentionCodeSeeder::class => [
'intention_codes',
],
SmrAreaSeeder::class => [
'smr_area',
],
];

const OTHER_TABLES_TO_TRUNCATE = [
Expand Down
20 changes: 20 additions & 0 deletions database/seeds/SmrAreaSeeder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use App\Models\SmrArea;
use Illuminate\Database\Seeder;

class SmrAreaSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
SmrArea::create([
'airfield_id' => 1,
'coordinates' => str_repeat("COORD:N000.00.00.000:E000.00.00.000\n", 3),
'start_date' => null,
'end_date' => null,
]);
}
}
1 change: 1 addition & 0 deletions lang/en/filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
'notifications' => require_once __DIR__ . '/notifications/filter.php',
'runways' => require_once __DIR__ . '/runways/filter.php',
'sids' => require_once __DIR__ . '/sids/filter.php',
'smr_areas' => require_once __DIR__ . '/smr_areas/filter.php',
'stands' => require_once __DIR__ . '/stands/filter.php',
];
15 changes: 8 additions & 7 deletions lang/en/form.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
'aircraft' => require_once __DIR__ . '/aircraft/form.php',
'airfields' => require_once __DIR__ . '/airfields/form.php',
'airlines' => require_once __DIR__ . '/airlines/form.php',
'controllers' => require_once __DIR__ . '/controllers/form.php',
'fir_exit_points' => require_once __DIR__ . '/fir_exit_points/form.php',
'intention' => require_once __DIR__ . '/intention/form.php',
'stands' => require_once __DIR__ . '/stands/form.php',
'users' => require_once __DIR__ . '/users/form.php',
'sids' => require_once __DIR__ . '/sids/form.php',
'handoffs' => require_once __DIR__ . '/handoffs/form.php',
'holds' => require_once __DIR__ . '/holds/form.php',
'intention' => require_once __DIR__ . '/intention/form.php',
'navaids' => require_once __DIR__ . '/navaids/form.php',
'notifications' => require_once __DIR__ . '/notifications/form.php',
'plugin' => require_once __DIR__ . '/plugin/form.php',
'prenotes' => require_once __DIR__ . '/prenotes/form.php',
'runways' => require_once __DIR__ . '/runways/form.php',
'controllers' => require_once __DIR__ . '/controllers/form.php',
'navaids' => require_once __DIR__ . '/navaids/form.php',
'notifications' => require_once __DIR__ . '/notifications/form.php',
'sids' => require_once __DIR__ . '/sids/form.php',
'smr_areas' => require_once __DIR__ . '/smr_areas/form.php',
'squawks' => require_once __DIR__ . '/squawks/form.php',
'srd' => require_once __DIR__ . '/srd/form.php',
'stands' => require_once __DIR__ . '/stands/form.php',
'terminals' => require_once __DIR__ . '/terminals/form.php',
'users' => require_once __DIR__ . '/users/form.php',
];
10 changes: 10 additions & 0 deletions lang/en/smr_areas/filter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

return [
'activation' => [
'label' => 'Activation',
'true' => 'Active',
'false' => 'Inactive',
],
'expired' => 'Expired',
];
Loading
Loading