13 Commits

Author SHA1 Message Date
rlong cee16de419 Add Gitea Action for deployment and optimization 2026-05-06 15:30:50 -04:00
rlong e4cccba942 Merge pull request 'change button color' (#9) from feature/all-searchable-selects into master
Reviewed-on: #9
2026-04-30 15:39:37 -04:00
rlong e023f68a84 change button color 2026-04-30 15:38:39 -04:00
rlong 4edb7fac10 Merge pull request 'feat: implement global searchable selects using Select2 and remove redundant per-view implementations' (#8) from feature/all-searchable-selects into master
Reviewed-on: #8
2026-04-30 15:36:37 -04:00
rlong 19f93f95bb feat: implement global searchable selects using Select2 and remove redundant per-view implementations 2026-04-30 15:33:34 -04:00
rlong 885161cc2b Merge pull request 'Add seeders and factories for all models' (#7) from feature/add-model-seeders into master
Reviewed-on: #7
2026-04-29 20:39:40 -04:00
rlong a8fd03f256 Add seeders and factories for all models 2026-04-29 20:38:05 -04:00
rlong 00ff08e3a6 Enable profile and add OIDC menu item to Filament panel configuration 2026-04-26 17:10:28 -04:00
rlong 7e8b35bf20 Add Link OIDC Account and Admin links to frontend user menu 2026-04-26 17:09:52 -04:00
rlong 681d8b73d6 Move OIDC menu item registration to boot method for reliability 2026-04-26 17:08:00 -04:00
rlong f294ded6e8 fix resource 2026-04-26 16:46:28 -04:00
rlong eca564eac7 fix userresource 2026-04-26 16:44:17 -04:00
rlong e8df889f7e Merge pull request 'Implement OIDC authentication via Laravel Socialite' (#6) from feature/socialite-oidc-auth into master
Reviewed-on: #6
2026-04-26 16:39:34 -04:00
24 changed files with 429 additions and 168 deletions
+29
View File
@@ -0,0 +1,29 @@
name: Deploy to Remote Server
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Deploy and optimize
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT || 22 }}
script: |
cd ${{ secrets.DEPLOY_PATH }}
git pull origin master
composer install --no-interaction --prefer-dist --optimize-autoloader
npm install
npm run prod
php artisan migrate --force
php artisan optimize:clear
+2 -1
View File
@@ -13,6 +13,7 @@ use Filament\Actions\EditAction;
use Filament\Actions\BulkActionGroup; use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction; use Filament\Actions\DeleteBulkAction;
use Filament\Support\Icons\Heroicon; use Filament\Support\Icons\Heroicon;
use BackedEnum;
class UserResource extends Resource class UserResource extends Resource
{ {
@@ -20,7 +21,7 @@ class UserResource extends Resource
protected static ?string $recordTitleAttribute = 'name'; protected static ?string $recordTitleAttribute = 'name';
protected static string | \UnitEnum | null $navigationIcon = 'heroicon-o-users'; protected static string | BackedEnum | null $navigationIcon = 'heroicon-o-users';
public static function form(Schema $schema): Schema public static function form(Schema $schema): Schema
{ {
+13 -3
View File
@@ -23,6 +23,8 @@ use Illuminate\Support\Facades\Blade;
use Filament\Navigation\MenuItem; use Filament\Navigation\MenuItem;
use Filament\Facades\Filament;
class AdminPanelProvider extends PanelProvider class AdminPanelProvider extends PanelProvider
{ {
public function boot() public function boot()
@@ -42,6 +44,13 @@ class AdminPanelProvider extends PanelProvider
</div> </div>
'), '),
); );
Filament::registerUserMenuItems([
MenuItem::make()
->label('Link OIDC Account')
->icon('heroicon-o-link')
->url(fn (): string => url('auth/social/oidc')),
]);
} }
public function panel(Panel $panel): Panel public function panel(Panel $panel): Panel
@@ -51,14 +60,15 @@ class AdminPanelProvider extends PanelProvider
->id('admin') ->id('admin')
->path('admin') ->path('admin')
->login() ->login()
->brandName(env('APP_NAME')) ->profile()
->homeUrl('/')
->userMenuItems([ ->userMenuItems([
MenuItem::make() 'oidc' => MenuItem::make()
->label('Link OIDC Account') ->label('Link OIDC Account')
->icon('heroicon-o-link') ->icon('heroicon-o-link')
->url(fn (): string => url('auth/social/oidc')), ->url(fn (): string => url('auth/social/oidc')),
]) ])
->brandName(env('APP_NAME'))
->homeUrl('/')
->colors([ ->colors([
'primary' => Color::Amber, 'primary' => Color::Amber,
]) ])
+125 -8
View File
@@ -23,14 +23,131 @@ $factory->define(App\User::class, function (Faker\Generator $faker) {
]; ];
}); });
//Bidder // Bidders
$factory->define(App\Models\Bidder::class, function (Faker\Generator $faker) { $factory->define(App\Models\Bidders::class, function (Faker\Generator $faker) {
static $password;
return [ return [
'name' => $faker->name, 'bidder_fname' => $faker->firstName,
'email' => $faker->unique()->safeEmail, 'bidder_lname' => $faker->lastName,
'password' => $password ?: $password = bcrypt('secret'), 'bidder_addr' => $faker->streetAddress,
'remember_token' => str_random(10), 'bidder_city' => $faker->city,
'bidder_state' => $faker->stateAbbr,
'bidder_zip' => $faker->postcode,
'bidder_phone' => $faker->phoneNumber,
'bidder_email' => $faker->unique()->safeEmail,
'bidder_assigned_number' => $faker->unique()->numberBetween(1, 1000),
];
});
// Items
$factory->define(App\Models\Items::class, function (Faker\Generator $faker) {
return [
'item_desc' => $faker->sentence(3),
'item_min_bid' => $faker->numberBetween(10, 100),
'item_est_value' => $faker->numberBetween(50, 500),
'item_assigned_num' => $faker->unique()->numberBetween(1, 500),
];
});
// CarShowCategory
$factory->define(App\Models\CarShowCategory::class, function (Faker\Generator $faker) {
return [
'category_name' => $faker->words(2, true),
'vehicle_type' => $faker->boolean,
];
});
// Vehicles
$factory->define(App\Models\Vehicles::class, function (Faker\Generator $faker) {
return [
'year' => $faker->year,
'make' => $faker->company,
'model' => $faker->word,
'type' => function () {
return factory(App\Models\CarShowCategory::class)->create()->id;
},
'doNotJudge' => $faker->boolean,
'owner' => function () {
return factory(App\Models\Bidders::class)->create()->bidder_assigned_number;
},
];
});
// PaymentMethods
$factory->define(App\Models\PaymentMethods::class, function (Faker\Generator $faker) {
return [
'pm_name' => $faker->randomElement(['Cash', 'Check', 'Credit Card']),
];
});
// Judges
$factory->define(App\Models\Judges::class, function (Faker\Generator $faker) {
return [
'judge_number' => $faker->unique()->numberBetween(1, 50),
];
});
// VehicleScores
$factory->define(App\Models\VehicleScores::class, function (Faker\Generator $faker) {
return [
'judge' => function () {
return factory(App\Models\Judges::class)->create()->id;
},
'overall_score' => $faker->numberBetween(1, 100),
'vehicle' => function () {
return factory(App\Models\Vehicles::class)->create()->id;
},
];
});
// PeoplesChoice
$factory->define(App\Models\PeoplesChoice::class, function (Faker\Generator $faker) {
return [
'vehicle' => function () {
return factory(App\Models\Vehicles::class)->create()->id;
},
'pc_count' => $faker->numberBetween(0, 50),
];
});
// WinningBids
$factory->define(App\Models\WinningBids::class, function (Faker\Generator $faker) {
return [
'winning_bidder_num' => function () {
return factory(App\Models\Bidders::class)->create()->idbidders;
},
'winning_cost' => $faker->numberBetween(10, 1000),
'winning_item_num' => function () {
return factory(App\Models\Items::class)->create()->iditems;
},
];
});
// Checkout
$factory->define(App\Models\Checkout::class, function (Faker\Generator $faker) {
return [
'bidder_num' => function () {
return factory(App\Models\Bidders::class)->create()->idbidders;
},
'winnertotal' => $faker->numberBetween(10, 2000),
'payment_method' => function () {
return factory(App\Models\PaymentMethods::class)->create()->pm_id;
},
'check_number' => $faker->optional()->numberBetween(100, 999),
'cc_transaction' => $faker->optional()->uuid,
'cc_amount' => $faker->optional()->numberBetween(10, 2000),
];
});
// CarShowWinner
$factory->define(App\Models\CarShowWinner::class, function (Faker\Generator $faker) {
return [
'vehicle' => function () {
return factory(App\Models\Vehicles::class)->create()->id;
},
'category' => function () {
return factory(App\Models\CarShowCategory::class)->create()->id;
},
'place' => $faker->numberBetween(1, 3),
'total_score' => $faker->numberBetween(50, 300),
]; ];
}); });
+12
View File
@@ -0,0 +1,12 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\Bidders;
class BiddersTableSeeder extends Seeder
{
public function run()
{
factory(Bidders::class, 50)->create();
}
}
@@ -0,0 +1,12 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\CarShowCategory;
class CarShowCategoryTableSeeder extends Seeder
{
public function run()
{
factory(CarShowCategory::class, 10)->create();
}
}
@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\CarShowWinner;
use App\Models\Vehicles;
use App\Models\CarShowCategory;
class CarShowWinnerTableSeeder extends Seeder
{
public function run()
{
$categories = CarShowCategory::all();
$vehicles = Vehicles::all();
foreach ($categories as $category) {
for ($i = 1; $i <= 3; $i++) {
factory(CarShowWinner::class)->create([
'category' => $category->id,
'vehicle' => $vehicles->random()->id,
'place' => $i,
]);
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\Checkout;
use App\Models\Bidders;
use App\Models\PaymentMethods;
class CheckoutTableSeeder extends Seeder
{
public function run()
{
$bidders = Bidders::all();
$paymentMethods = PaymentMethods::all();
foreach ($bidders as $bidder) {
if (rand(0, 1)) {
factory(Checkout::class)->create([
'bidder_num' => $bidder->idbidders,
'payment_method' => $paymentMethods->random()->pm_id,
]);
}
}
}
}
+12 -1
View File
@@ -11,6 +11,17 @@ class DatabaseSeeder extends Seeder
*/ */
public function run() public function run()
{ {
// $this->call(UsersTableSeeder::class); $this->call(UsersTableSeeder::class);
$this->call(PaymentMethodsTableSeeder::class);
$this->call(CarShowCategoryTableSeeder::class);
$this->call(BiddersTableSeeder::class);
$this->call(ItemsTableSeeder::class);
$this->call(JudgesTableSeeder::class);
$this->call(VehiclesTableSeeder::class);
$this->call(VehicleScoresTableSeeder::class);
$this->call(PeoplesChoiceTableSeeder::class);
$this->call(WinningBidsTableSeeder::class);
$this->call(CheckoutTableSeeder::class);
$this->call(CarShowWinnerTableSeeder::class);
} }
} }
+12
View File
@@ -0,0 +1,12 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\Items;
class ItemsTableSeeder extends Seeder
{
public function run()
{
factory(Items::class, 30)->create();
}
}
+12
View File
@@ -0,0 +1,12 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\Judges;
class JudgesTableSeeder extends Seeder
{
public function run()
{
factory(Judges::class, 5)->create();
}
}
@@ -0,0 +1,14 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\PaymentMethods;
class PaymentMethodsTableSeeder extends Seeder
{
public function run()
{
PaymentMethods::create(['pm_name' => 'Cash']);
PaymentMethods::create(['pm_name' => 'Check']);
PaymentMethods::create(['pm_name' => 'Credit Card']);
}
}
@@ -0,0 +1,19 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\PeoplesChoice;
use App\Models\Vehicles;
class PeoplesChoiceTableSeeder extends Seeder
{
public function run()
{
$vehicles = Vehicles::all();
foreach ($vehicles as $vehicle) {
factory(PeoplesChoice::class)->create([
'vehicle' => $vehicle->id,
]);
}
}
}
+12
View File
@@ -0,0 +1,12 @@
<?php
use Illuminate\Database\Seeder;
use App\User;
class UsersTableSeeder extends Seeder
{
public function run()
{
factory(User::class, 10)->create();
}
}
@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\VehicleScores;
use App\Models\Judges;
use App\Models\Vehicles;
class VehicleScoresTableSeeder extends Seeder
{
public function run()
{
$judges = Judges::all();
$vehicles = Vehicles::all();
foreach ($vehicles as $vehicle) {
foreach ($judges as $judge) {
factory(VehicleScores::class)->create([
'judge' => $judge->id,
'vehicle' => $vehicle->id,
]);
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\Vehicles;
use App\Models\CarShowCategory;
use App\Models\Bidders;
class VehiclesTableSeeder extends Seeder
{
public function run()
{
$categories = CarShowCategory::all();
$bidders = Bidders::all();
factory(Vehicles::class, 40)->create([
'type' => function () use ($categories) {
return $categories->random()->id;
},
'owner' => function () use ($bidders) {
return $bidders->random()->bidder_assigned_number;
},
]);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Seeder;
use App\Models\WinningBids;
use App\Models\Bidders;
use App\Models\Items;
class WinningBidsTableSeeder extends Seeder
{
public function run()
{
$bidders = Bidders::all();
$items = Items::all();
foreach ($items as $item) {
if (rand(0, 1)) {
factory(WinningBids::class)->create([
'winning_bidder_num' => $bidders->random()->idbidders,
'winning_item_num' => $item->iditems,
]);
}
}
}
}
+1 -1
View File
@@ -54,7 +54,7 @@
Login Login
</button> </button>
<a href="{{ url('auth/social/oidc') }}" class="btn btn-info"> <a href="{{ url('auth/social/oidc') }}" class="btn btn-primary">
Login with OIDC Login with OIDC
</a> </a>
@@ -1,22 +1,5 @@
@extends('layouts.app') @extends('layouts.app')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
.select2-container .select2-selection--single {
height: 34px;
border: 1px solid #ccc;
border-radius: 4px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 34px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 32px;
}
</style>
@endpush
@section('content') @section('content')
<div class="container"> <div class="container">
<div class="row"> <div class="row">
@@ -49,15 +32,3 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('#checkoutbiddernum').select2({
placeholder: "Select a bidder",
allowClear: true
});
});
</script>
@endpush
-33
View File
@@ -1,22 +1,5 @@
@extends('layouts.app') @extends('layouts.app')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
.select2-container .select2-selection--single {
height: 34px;
border: 1px solid #ccc;
border-radius: 4px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 34px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 32px;
}
</style>
@endpush
@section('content') @section('content')
<div class="container"> <div class="container">
<div class="row"> <div class="row">
@@ -66,19 +49,3 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('#winid').select2({
placeholder: "Select an item/winner",
allowClear: true
});
$('#winnerbiddernum').select2({
placeholder: "Select a bidder",
allowClear: true
});
});
</script>
@endpush
+33
View File
@@ -12,6 +12,20 @@
<!-- Styles --> <!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet"> <link href="{{ asset('css/app.css') }}" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
.select2-container .select2-selection--single {
height: 34px;
border: 1px solid #ccc;
border-radius: 4px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 34px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 32px;
}
</style>
@stack('styles') @stack('styles')
</head> </head>
<body> <body>
@@ -221,6 +235,16 @@
</a> </a>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li>
<a href="{{ url('admin') }}">
Admin
</a>
</li>
<li>
<a href="{{ url('auth/social/oidc') }}">
Link OIDC Account
</a>
</li>
<li> <li>
<a href="{{ route('logout') }}" <a href="{{ route('logout') }}"
onclick="event.preventDefault(); onclick="event.preventDefault();
@@ -245,6 +269,15 @@
<!-- Scripts --> <!-- Scripts -->
<script src="{{ asset('js/app.js') }}"></script> <script src="{{ asset('js/app.js') }}"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('select').select2({
placeholder: "Select an option",
allowClear: true
});
});
</script>
@stack('scripts') @stack('scripts')
</body> </body>
</html> </html>
@@ -1,22 +1,5 @@
@extends('layouts.app') @extends('layouts.app')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
.select2-container .select2-selection--single {
height: 34px;
border: 1px solid #ccc;
border-radius: 4px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 34px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 32px;
}
</style>
@endpush
@section('content') @section('content')
<div class="container"> <div class="container">
<div class="row"> <div class="row">
@@ -49,15 +32,3 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('#reprintbiddernum').select2({
placeholder: "Select a bidder",
allowClear: true
});
});
</script>
@endpush
-34
View File
@@ -1,22 +1,5 @@
@extends('layouts.app') @extends('layouts.app')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
.select2-container .select2-selection--single {
height: 34px;
border: 1px solid #ccc;
border-radius: 4px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 34px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 32px;
}
</style>
@endpush
@section('content') @section('content')
<div class="container"> <div class="container">
<div class="row"> <div class="row">
@@ -67,20 +50,3 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('#winnerbiddernum').select2({
placeholder: "Select a bidder",
allowClear: true
});
// Also making item number searchable as it's generally expected for "typed in" lookups
$('#winneritemnum').select2({
placeholder: "Select an item",
allowClear: true
});
});
</script>
@endpush
-29
View File
@@ -1,22 +1,5 @@
@extends('layouts.app') @extends('layouts.app')
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
.select2-container .select2-selection--single {
height: 34px;
border: 1px solid #ccc;
border-radius: 4px;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 34px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 32px;
}
</style>
@endpush
@section('content') @section('content')
<div class="container"> <div class="container">
<div class="row"> <div class="row">
@@ -49,15 +32,3 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('#winnerbiddernum').select2({
placeholder: "Select a bidder",
allowClear: true
});
});
</script>
@endpush