From 9b8d73de5aa0ed0a50468a0441208ea417ed28fb Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Wed, 10 Jun 2026 14:56:43 +0100 Subject: [PATCH] major update --- AGENTS.md | 1 - FIX_NOTES.md | 22 +++ FIX_NOTES_PLATFORM_CONFIG_MENU.md | 35 +++++ Feature/Auth/AuthenticationTest.php | 81 +++++++++++ Feature/Auth/EmailVerificationTest.php | 88 ++++++++++++ Feature/Auth/PasswordConfirmationTest.php | 21 +++ Feature/Auth/PasswordResetTest.php | 81 +++++++++++ Feature/Auth/RegistrationTest.php | 41 ++++++ Feature/Auth/TwoFactorChallengeTest.php | 42 ++++++ Feature/DashboardTest.php | 27 ++++ Feature/ExampleTest.php | 18 +++ Feature/Settings/ProfileUpdateTest.php | 90 ++++++++++++ Feature/Settings/SecurityTest.php | 132 ++++++++++++++++++ TestCase.php | 44 ++++++ Unit/ExampleTest.php | 16 +++ composer.json | 1 - filament/ColumnView.stub | 3 + filament/ComponentView.stub | 3 + filament/EntryView.stub | 8 ++ filament/FieldView.stub | 11 ++ filament/LivewireFormView.stub | 11 ++ filament/LivewireSchemaView.stub | 5 + filament/LivewireTableView.stub | 3 + filament/PageView.stub | 3 + .../RichContentCustomBlockPreviewView.stub | 3 + filament/RichContentCustomBlockView.stub | 3 + filament/ThemeCss.stub | 4 + filament/WidgetView.stub | 5 + mcp-app-resource.stub | 24 ++++ mcp-app-resource.view.stub | 17 +++ mcp-prompt.stub | 35 +++++ mcp-resource.stub | 22 +++ mcp-server.stub | 26 ++++ mcp-tool.stub | 35 +++++ resources/css/app.css | 58 +++++++- resources/views/layouts/app/sidebar.blade.php | 29 ++-- storage/framework/cache/.gitkeep | 0 .../db73a299c44034f39f71d9fea75fba3c.php | 29 ++-- .../Concerns/CreatesWmsBrowserData.php | 98 +++++++++++++ .../Concerns/TestsResponsiveBreakpoints.php | 46 ++++++ tests/Browser/PlatformAdminUiTest.php | 95 +++++++++++++ tests/Browser/WarehouseUiTest.php | 87 ++++++++++++ tests/Browser/WmsResponsiveShellTest.php | 104 ++++++++++++++ tests/DuskTestCase.php | 29 ++-- .../Modules/ModulePlaceholderPageTest.php | 65 +++++++++ .../Modules/PlatformAdminUiFlowTest.php | 88 ++++++++++++ tests/Feature/Modules/WarehouseUiFlowTest.php | 85 +++++++++++ 47 files changed, 1712 insertions(+), 62 deletions(-) create mode 100644 FIX_NOTES.md create mode 100644 FIX_NOTES_PLATFORM_CONFIG_MENU.md create mode 100644 Feature/Auth/AuthenticationTest.php create mode 100644 Feature/Auth/EmailVerificationTest.php create mode 100644 Feature/Auth/PasswordConfirmationTest.php create mode 100644 Feature/Auth/PasswordResetTest.php create mode 100644 Feature/Auth/RegistrationTest.php create mode 100644 Feature/Auth/TwoFactorChallengeTest.php create mode 100644 Feature/DashboardTest.php create mode 100644 Feature/ExampleTest.php create mode 100644 Feature/Settings/ProfileUpdateTest.php create mode 100644 Feature/Settings/SecurityTest.php create mode 100644 TestCase.php create mode 100644 Unit/ExampleTest.php create mode 100644 filament/ColumnView.stub create mode 100644 filament/ComponentView.stub create mode 100644 filament/EntryView.stub create mode 100644 filament/FieldView.stub create mode 100644 filament/LivewireFormView.stub create mode 100644 filament/LivewireSchemaView.stub create mode 100644 filament/LivewireTableView.stub create mode 100644 filament/PageView.stub create mode 100644 filament/RichContentCustomBlockPreviewView.stub create mode 100644 filament/RichContentCustomBlockView.stub create mode 100644 filament/ThemeCss.stub create mode 100644 filament/WidgetView.stub create mode 100644 mcp-app-resource.stub create mode 100644 mcp-app-resource.view.stub create mode 100644 mcp-prompt.stub create mode 100644 mcp-resource.stub create mode 100644 mcp-server.stub create mode 100644 mcp-tool.stub create mode 100644 storage/framework/cache/.gitkeep create mode 100644 tests/Browser/Concerns/CreatesWmsBrowserData.php create mode 100644 tests/Browser/Concerns/TestsResponsiveBreakpoints.php create mode 100644 tests/Browser/PlatformAdminUiTest.php create mode 100644 tests/Browser/WarehouseUiTest.php create mode 100644 tests/Browser/WmsResponsiveShellTest.php create mode 100644 tests/Feature/Modules/ModulePlaceholderPageTest.php create mode 100644 tests/Feature/Modules/PlatformAdminUiFlowTest.php create mode 100644 tests/Feature/Modules/WarehouseUiFlowTest.php diff --git a/AGENTS.md b/AGENTS.md index 84a15dd6..a5325d82 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,7 +20,6 @@ This application is a Laravel application and its main Laravel ecosystems packag - livewire/flux (FLUXUI_FREE) - v2 - livewire/livewire (LIVEWIRE) - v4 - laravel/boost (BOOST) - v2 -- laravel/dusk (DUSK) - v8 - laravel/mcp (MCP) - v0 - laravel/pail (PAIL) - v1 - laravel/pint (PINT) - v1 diff --git a/FIX_NOTES.md b/FIX_NOTES.md new file mode 100644 index 00000000..d31575b3 --- /dev/null +++ b/FIX_NOTES.md @@ -0,0 +1,22 @@ +# WMS Fix Notes + +This build patches only the current uploaded code. + +## Fixed + +- Duplicate two-factor migration made safe. +- Primary two-factor migration adds columns one at a time for SQLite safety. +- Module page slot is wrapped in a visible `.wms-content` main container. +- Sidebar remains traditional: desktop/tablet icon rail, mobile drawer. +- Sidebar widened for "Warehouse Management System". +- Laravel cache folders are included so "Please provide a valid cache path" does not recur after unzip. + +## After unzip + +```bash +composer install +npm install +php artisan optimize:clear +php artisan test +npm run build +``` diff --git a/FIX_NOTES_PLATFORM_CONFIG_MENU.md b/FIX_NOTES_PLATFORM_CONFIG_MENU.md new file mode 100644 index 00000000..da2a0f0b --- /dev/null +++ b/FIX_NOTES_PLATFORM_CONFIG_MENU.md @@ -0,0 +1,35 @@ +# Platform config and module menu fix + +Applied fixes: + +- Added `Modules/Platform/config/platform.php`. +- Hardened `Modules/Platform/Providers/PlatformServiceProvider.php` so config loading is safe. +- Removed stale generated files from `bootstrap/cache`. +- Updated `resources/views/layouts/app.blade.php` so it works for both: + - component pages using `` + - legacy placeholder module pages using `@extends('layouts.app')` and `@section('content')` +- Added placeholder module entries to the left navigation: + - Inventory Management + - Shipping + - Carrier Management + - Transportation + - Replenishment + - M3 Integration + - Document Archive + - Analytics + - Reporting + - Audit + - Security + - Configuration +- Added compatibility CSS for the placeholder module pages that use Bootstrap-style classes. +- Ensured cache/runtime directories exist. + +Run: + +```bash +composer install +npm install +php artisan optimize:clear +php artisan test +npm run build +``` diff --git a/Feature/Auth/AuthenticationTest.php b/Feature/Auth/AuthenticationTest.php new file mode 100644 index 00000000..49e27d17 --- /dev/null +++ b/Feature/Auth/AuthenticationTest.php @@ -0,0 +1,81 @@ +get(route('login')); + + $response->assertOk(); + } + + public function test_users_can_authenticate_using_the_login_screen(): void + { + $user = User::factory()->create(); + + $response = $this->csrfPost(route('login.store'), [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('dashboard', absolute: false)); + + $this->assertAuthenticated(); + } + + public function test_users_can_not_authenticate_with_invalid_password(): void + { + $user = User::factory()->create(); + + $response = $this->csrfPost(route('login.store'), [ + 'email' => $user->email, + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrorsIn('email'); + + $this->assertGuest(); + } + + public function test_users_with_two_factor_enabled_are_redirected_to_two_factor_challenge(): void + { + $this->skipUnlessFortifyHas(Features::twoFactorAuthentication()); + + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + ]); + + $user = User::factory()->withTwoFactor()->create(); + + $response = $this->csrfPost(route('login.store'), [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $response->assertRedirect(route('two-factor.login')); + $this->assertGuest(); + } + + public function test_users_can_logout(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->csrfPost(route('logout')); + + $response->assertRedirect(route('home')); + + $this->assertGuest(); + } +} diff --git a/Feature/Auth/EmailVerificationTest.php b/Feature/Auth/EmailVerificationTest.php new file mode 100644 index 00000000..c434b63a --- /dev/null +++ b/Feature/Auth/EmailVerificationTest.php @@ -0,0 +1,88 @@ +skipUnlessFortifyHas(Features::emailVerification()); + } + + public function test_email_verification_screen_can_be_rendered(): void + { + $user = User::factory()->unverified()->create(); + + $response = $this->actingAs($user)->get(route('verification.notice')); + + $response->assertOk(); + } + + public function test_email_can_be_verified(): void + { + $user = User::factory()->unverified()->create(); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)], + ); + + $response = $this->actingAs($user)->get($verificationUrl); + + Event::assertDispatched(Verified::class); + + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + $response->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + } + + public function test_email_is_not_verified_with_invalid_hash(): void + { + $user = User::factory()->unverified()->create(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1('wrong-email')], + ); + + $this->actingAs($user)->get($verificationUrl); + + $this->assertFalse($user->fresh()->hasVerifiedEmail()); + } + + public function test_already_verified_user_visiting_verification_link_is_redirected_without_firing_event_again(): void + { + $user = User::factory()->create([ + 'email_verified_at' => now(), + ]); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)], + ); + + $this->actingAs($user)->get($verificationUrl) + ->assertRedirect(route('dashboard', absolute: false).'?verified=1'); + + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + Event::assertNotDispatched(Verified::class); + } +} diff --git a/Feature/Auth/PasswordConfirmationTest.php b/Feature/Auth/PasswordConfirmationTest.php new file mode 100644 index 00000000..b86e36c1 --- /dev/null +++ b/Feature/Auth/PasswordConfirmationTest.php @@ -0,0 +1,21 @@ +create(); + + $response = $this->actingAs($user)->get(route('password.confirm')); + + $response->assertOk(); + } +} diff --git a/Feature/Auth/PasswordResetTest.php b/Feature/Auth/PasswordResetTest.php new file mode 100644 index 00000000..93673ed8 --- /dev/null +++ b/Feature/Auth/PasswordResetTest.php @@ -0,0 +1,81 @@ +skipUnlessFortifyHas(Features::resetPasswords()); + } + + public function test_reset_password_link_screen_can_be_rendered(): void + { + $response = $this->get(route('password.request')); + + $response->assertOk(); + } + + public function test_reset_password_link_can_be_requested(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->csrfPost(route('password.email'), ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class); + } + + public function test_reset_password_screen_can_be_rendered(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->csrfPost(route('password.email'), ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $response = $this->get(route('password.reset', $notification->token)); + + $response->assertOk(); + + return true; + }); + } + + public function test_password_can_be_reset_with_valid_token(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->csrfPost(route('password.email'), ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $response = $this->csrfPost(route('password.update'), [ + 'token' => $notification->token, + 'email' => $user->email, + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('login', absolute: false)); + + return true; + }); + } +} diff --git a/Feature/Auth/RegistrationTest.php b/Feature/Auth/RegistrationTest.php new file mode 100644 index 00000000..7837d049 --- /dev/null +++ b/Feature/Auth/RegistrationTest.php @@ -0,0 +1,41 @@ +skipUnlessFortifyHas(Features::registration()); + } + + public function test_registration_screen_can_be_rendered(): void + { + $response = $this->get(route('register')); + + $response->assertOk(); + } + + public function test_new_users_can_register(): void + { + $response = $this->csrfPost(route('register.store'), [ + 'name' => 'John Doe', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response->assertSessionHasNoErrors() + ->assertRedirect(route('dashboard', absolute: false)); + + $this->assertAuthenticated(); + } +} diff --git a/Feature/Auth/TwoFactorChallengeTest.php b/Feature/Auth/TwoFactorChallengeTest.php new file mode 100644 index 00000000..a8fc8aef --- /dev/null +++ b/Feature/Auth/TwoFactorChallengeTest.php @@ -0,0 +1,42 @@ +skipUnlessFortifyHas(Features::twoFactorAuthentication()); + } + + public function test_two_factor_challenge_redirects_to_login_when_not_authenticated(): void + { + $response = $this->get(route('two-factor.login')); + + $response->assertRedirect(route('login')); + } + + public function test_two_factor_challenge_can_be_rendered(): void + { + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + ]); + + $user = User::factory()->withTwoFactor()->create(); + + $this->csrfPost(route('login.store'), [ + 'email' => $user->email, + 'password' => 'password', + ])->assertRedirect(route('two-factor.login')); + } +} diff --git a/Feature/DashboardTest.php b/Feature/DashboardTest.php new file mode 100644 index 00000000..3c5cd7da --- /dev/null +++ b/Feature/DashboardTest.php @@ -0,0 +1,27 @@ +get(route('dashboard')); + $response->assertRedirect(route('login')); + } + + public function test_authenticated_users_can_visit_the_dashboard(): void + { + $user = User::factory()->create(); + $this->actingAs($user); + + $response = $this->get(route('dashboard')); + $response->assertOk(); + } +} diff --git a/Feature/ExampleTest.php b/Feature/ExampleTest.php new file mode 100644 index 00000000..70d12f02 --- /dev/null +++ b/Feature/ExampleTest.php @@ -0,0 +1,18 @@ +get(route('home')); + + $response->assertOk(); + } +} diff --git a/Feature/Settings/ProfileUpdateTest.php b/Feature/Settings/ProfileUpdateTest.php new file mode 100644 index 00000000..fccf19fd --- /dev/null +++ b/Feature/Settings/ProfileUpdateTest.php @@ -0,0 +1,90 @@ +actingAs($user = User::factory()->create()); + + $this->get('/settings/profile')->assertOk(); + } + + public function test_profile_information_can_be_updated(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test(Profile::class) + ->set('name', 'Test User') + ->set('email', 'test@example.com') + ->call('updateProfileInformation'); + + $response->assertHasNoErrors(); + + $user->refresh(); + + $this->assertEquals('Test User', $user->name); + $this->assertEquals('test@example.com', $user->email); + $this->assertNull($user->email_verified_at); + } + + public function test_email_verification_status_is_unchanged_when_email_address_is_unchanged(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test(Profile::class) + ->set('name', 'Test User') + ->set('email', $user->email) + ->call('updateProfileInformation'); + + $response->assertHasNoErrors(); + + $this->assertNotNull($user->refresh()->email_verified_at); + } + + public function test_user_can_delete_their_account(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test('settings.delete-user-form') + ->set('password', 'password') + ->call('deleteUser'); + + $response + ->assertHasNoErrors() + ->assertRedirect('/'); + + $this->assertNull($user->fresh()); + $this->assertFalse(auth()->check()); + } + + public function test_correct_password_must_be_provided_to_delete_account(): void + { + $user = User::factory()->create(); + + $this->actingAs($user); + + $response = Livewire::test('settings.delete-user-form') + ->set('password', 'wrong-password') + ->call('deleteUser'); + + $response->assertHasErrors(['password']); + + $this->assertNotNull($user->fresh()); + } +} diff --git a/Feature/Settings/SecurityTest.php b/Feature/Settings/SecurityTest.php new file mode 100644 index 00000000..9bbb7ead --- /dev/null +++ b/Feature/Settings/SecurityTest.php @@ -0,0 +1,132 @@ +skipUnlessFortifyHas(Features::twoFactorAuthentication()); + + Features::twoFactorAuthentication([ + 'confirm' => true, + 'confirmPassword' => true, + ]); + Features::passkeys([ + 'confirmPassword' => true, + ]); + } + + public function test_security_settings_page_can_be_rendered(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user) + ->withSession(['auth.password_confirmed_at' => time()]) + ->get(route('security.edit')); + + $response->assertOk(); + + $response->assertSee('Passkeys'); + $response->assertSee('No passkeys yet'); + $response->assertSee('Two-factor authentication'); + $response->assertSee('Enable 2FA'); + } + + public function test_security_settings_page_requires_password_confirmation_when_enabled(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user) + ->get(route('security.edit')); + + $response->assertRedirect(route('password.confirm')); + } + + public function test_security_settings_page_renders_without_two_factor_when_feature_is_disabled(): void + { + config(['fortify.features' => []]); + + $user = User::factory()->create(); + + $this->actingAs($user) + ->withSession(['auth.password_confirmed_at' => time()]) + ->get(route('security.edit')) + ->assertOk() + ->assertSee('Update password') + ->assertDontSee('Manage your passkeys for passwordless sign-in') + ->assertDontSee('Add a passkey to sign in without a password') + ->assertDontSee('Two-factor authentication'); + } + + public function test_two_factor_authentication_disabled_when_confirmation_abandoned_between_requests(): void + { + $user = User::factory()->create(); + + $user->forceFill([ + 'two_factor_secret' => encrypt('test-secret'), + 'two_factor_recovery_codes' => encrypt(json_encode(['code1', 'code2'])), + 'two_factor_confirmed_at' => null, + ])->save(); + + $this->actingAs($user); + + $component = Livewire::test(Security::class); + + $component->assertSet('twoFactorEnabled', false); + + $this->assertDatabaseHas('users', [ + 'id' => $user->id, + 'two_factor_secret' => null, + 'two_factor_recovery_codes' => null, + ]); + } + + public function test_password_can_be_updated(): void + { + $user = User::factory()->create([ + 'password' => Hash::make('password'), + ]); + + $this->actingAs($user); + + $response = Livewire::test(Security::class) + ->set('current_password', 'password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + $response->assertHasNoErrors(); + + $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); + } + + public function test_correct_password_must_be_provided_to_update_password(): void + { + $user = User::factory()->create([ + 'password' => Hash::make('password'), + ]); + + $this->actingAs($user); + + $response = Livewire::test(Security::class) + ->set('current_password', 'wrong-password') + ->set('password', 'new-password') + ->set('password_confirmation', 'new-password') + ->call('updatePassword'); + + $response->assertHasErrors(['current_password']); + } +} diff --git a/TestCase.php b/TestCase.php new file mode 100644 index 00000000..78677242 --- /dev/null +++ b/TestCase.php @@ -0,0 +1,44 @@ + false, + 'session.driver' => 'array', + 'cache.default' => 'array', + 'mail.default' => 'array', + ]); + + $this->withoutMiddleware(ValidateCsrfToken::class); + } + + /** + * POST with a real CSRF token for Fortify/web form tests. + * + * @param array $data + */ + protected function csrfPost(string $uri, array $data = []): \Illuminate\Testing\TestResponse + { + $token = 'test-csrf-token'; + + return $this->withSession(['_token' => $token]) + ->post($uri, ['_token' => $token, ...$data]); + } + + protected function skipUnlessFortifyHas(string $feature, ?string $message = null): void + { + if (! Features::enabled($feature)) { + $this->markTestSkipped($message ?? "Fortify feature [{$feature}] is not enabled."); + } + } +} diff --git a/Unit/ExampleTest.php b/Unit/ExampleTest.php new file mode 100644 index 00000000..e93a27fa --- /dev/null +++ b/Unit/ExampleTest.php @@ -0,0 +1,16 @@ +assertTrue(true); + } +} diff --git a/composer.json b/composer.json index 53034903..16385d86 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,6 @@ "require-dev": { "fakerphp/faker": "^1.24", "laravel/boost": "^2.4", - "laravel/dusk": "^8.6", "laravel/pail": "^1.2.5", "laravel/pao": "^1.0.6", "laravel/pint": "^1.29", diff --git a/filament/ColumnView.stub b/filament/ColumnView.stub new file mode 100644 index 00000000..a9e74304 --- /dev/null +++ b/filament/ColumnView.stub @@ -0,0 +1,3 @@ +
+ {{ $getState() }} +
diff --git a/filament/ComponentView.stub b/filament/ComponentView.stub new file mode 100644 index 00000000..20ec68fe --- /dev/null +++ b/filament/ComponentView.stub @@ -0,0 +1,3 @@ +
+ {{-- Use $getChildSchema() to render the child schema() of this component. --}} +
diff --git a/filament/EntryView.stub b/filament/EntryView.stub new file mode 100644 index 00000000..e3e5f53a --- /dev/null +++ b/filament/EntryView.stub @@ -0,0 +1,8 @@ + +
+ {{ $getState() }} +
+
diff --git a/filament/FieldView.stub b/filament/FieldView.stub new file mode 100644 index 00000000..a8c9a008 --- /dev/null +++ b/filament/FieldView.stub @@ -0,0 +1,11 @@ + +
+ {{-- Interact with the `state` property in Alpine.js --}} +
+
diff --git a/filament/LivewireFormView.stub b/filament/LivewireFormView.stub new file mode 100644 index 00000000..bdddb320 --- /dev/null +++ b/filament/LivewireFormView.stub @@ -0,0 +1,11 @@ +
+
+ {{ $this->form }} + + +
+ + +
diff --git a/filament/LivewireSchemaView.stub b/filament/LivewireSchemaView.stub new file mode 100644 index 00000000..5507edb5 --- /dev/null +++ b/filament/LivewireSchemaView.stub @@ -0,0 +1,5 @@ +
+ {{ $this->content }} + + +
diff --git a/filament/LivewireTableView.stub b/filament/LivewireTableView.stub new file mode 100644 index 00000000..c3fedc4a --- /dev/null +++ b/filament/LivewireTableView.stub @@ -0,0 +1,3 @@ +
+ {{ $this->table }} +
diff --git a/filament/PageView.stub b/filament/PageView.stub new file mode 100644 index 00000000..bb8ed159 --- /dev/null +++ b/filament/PageView.stub @@ -0,0 +1,3 @@ + + {{-- Page content --}} + diff --git a/filament/RichContentCustomBlockPreviewView.stub b/filament/RichContentCustomBlockPreviewView.stub new file mode 100644 index 00000000..cd3a0532 --- /dev/null +++ b/filament/RichContentCustomBlockPreviewView.stub @@ -0,0 +1,3 @@ +
+ {{-- Custom block preview --}} +
diff --git a/filament/RichContentCustomBlockView.stub b/filament/RichContentCustomBlockView.stub new file mode 100644 index 00000000..eb70f329 --- /dev/null +++ b/filament/RichContentCustomBlockView.stub @@ -0,0 +1,3 @@ +
+ {{-- Custom block --}} +
diff --git a/filament/ThemeCss.stub b/filament/ThemeCss.stub new file mode 100644 index 00000000..91c829b1 --- /dev/null +++ b/filament/ThemeCss.stub @@ -0,0 +1,4 @@ +@import '../../../../vendor/filament/filament/resources/css/theme.css'; + +@source '../../../../app/Filament/{{ classDirectory }}**/*'; +@source '../../../../resources/views/filament/{{ viewDirectory }}**/*'; diff --git a/filament/WidgetView.stub b/filament/WidgetView.stub new file mode 100644 index 00000000..784d725c --- /dev/null +++ b/filament/WidgetView.stub @@ -0,0 +1,5 @@ + + + {{-- Widget content --}} + + diff --git a/mcp-app-resource.stub b/mcp-app-resource.stub new file mode 100644 index 00000000..c845ab68 --- /dev/null +++ b/mcp-app-resource.stub @@ -0,0 +1,24 @@ + $this->title(), + ]); + } +} diff --git a/mcp-app-resource.view.stub b/mcp-app-resource.view.stub new file mode 100644 index 00000000..2117c61c --- /dev/null +++ b/mcp-app-resource.view.stub @@ -0,0 +1,17 @@ + + + + + +
+ +

+
+
diff --git a/mcp-prompt.stub b/mcp-prompt.stub new file mode 100644 index 00000000..f9bb38c6 --- /dev/null +++ b/mcp-prompt.stub @@ -0,0 +1,35 @@ + + */ + public function arguments(): array + { + return [ + // + ]; + } +} diff --git a/mcp-resource.stub b/mcp-resource.stub new file mode 100644 index 00000000..62cd6828 --- /dev/null +++ b/mcp-resource.stub @@ -0,0 +1,22 @@ + + */ + public function schema(JsonSchema $schema): array + { + return [ + // + ]; + } +} diff --git a/resources/css/app.css b/resources/css/app.css index fd378106..2df09bc0 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -81,8 +81,8 @@ select:focus[data-flux-control] { top: 0; z-index: 40; display: flex; - width: 21.5rem; - min-width: 21.5rem; + width: 24rem; + min-width: 24rem; height: 100vh; flex-direction: column; border-right: 1px solid rgb(228 228 231); @@ -143,7 +143,7 @@ select:focus[data-flux-control] { } .wms-brand-title { - max-width: 16rem; + max-width: 18.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -164,6 +164,34 @@ select:focus[data-flux-control] { color: rgb(8 145 178); } + .wms-health-badge { + display: inline-flex; + align-items: center; + gap: 0.35rem; + border-radius: 999px; + border: 1px solid rgb(187 247 208); + background: rgb(220 252 231); + color: rgb(21 128 61); + padding: 0.38rem 0.58rem; + font-size: 0.72rem; + font-weight: 800; + text-decoration: none; + box-shadow: 0 10px 24px rgb(21 128 61 / 0.12); + transition: transform 120ms ease, background 120ms ease, border-color 120ms ease; + } + + .wms-health-badge:hover { + transform: translateY(-1px); + background: rgb(187 247 208); + border-color: rgb(134 239 172); + } + + .dark .wms-health-badge { + border-color: rgb(20 83 45); + background: rgb(20 83 45 / 0.55); + color: rgb(187 247 208); + } + .wms-sidebar-toggle, .wms-mobile-close, .wms-mobile-menu { @@ -277,6 +305,18 @@ select:focus[data-flux-control] { font-size: 1rem; } + .wms-platform-admin-link { + min-height: 3rem; + border: 1px solid rgb(14 116 144 / 0.28); + background: linear-gradient(135deg, rgb(8 47 73 / 0.12), rgb(14 116 144 / 0.08)); + font-weight: 800; + } + + .dark .wms-platform-admin-link { + border-color: rgb(103 232 249 / 0.22); + background: linear-gradient(135deg, rgb(8 47 73 / 0.75), rgb(20 83 45 / 0.25)); + } + .wms-sidebar-footer { display: grid; gap: 0.25rem; @@ -372,6 +412,10 @@ select:focus[data-flux-control] { display: none !important; } + html[data-wms-sidebar='collapsed'] .wms-health-badge { + display: none; + } + html[data-wms-sidebar='collapsed'] .wms-sidebar-header, html[data-wms-sidebar='collapsed'] .wms-sidebar-footer, html[data-wms-sidebar='collapsed'] .wms-sidebar-nav { @@ -411,8 +455,8 @@ select:focus[data-flux-control] { .wms-sidebar { position: fixed; inset: 0 auto 0 0; - width: min(21.5rem, calc(100vw - 2.5rem)); - min-width: min(21.5rem, calc(100vw - 2.5rem)); + width: min(24rem, calc(100vw - 2.5rem)); + min-width: min(24rem, calc(100vw - 2.5rem)); transform: translateX(-105%); box-shadow: 22px 0 60px rgb(0 0 0 / 0.24); } @@ -431,8 +475,8 @@ select:focus[data-flux-control] { } html[data-wms-sidebar='collapsed'] .wms-sidebar { - width: min(21.5rem, calc(100vw - 2.5rem)); - min-width: min(21.5rem, calc(100vw - 2.5rem)); + width: min(24rem, calc(100vw - 2.5rem)); + min-width: min(24rem, calc(100vw - 2.5rem)); } html[data-wms-sidebar='collapsed'] [data-wms-sidebar-label] { diff --git a/resources/views/layouts/app/sidebar.blade.php b/resources/views/layouts/app/sidebar.blade.php index 08411c7b..5de4eefa 100644 --- a/resources/views/layouts/app/sidebar.blade.php +++ b/resources/views/layouts/app/sidebar.blade.php @@ -21,6 +21,11 @@ + + + {{ __('OK') }} + +