diff --git a/resources/views/livewire/devices/configure.blade.php b/resources/views/livewire/devices/configure.blade.php index 93183cf..4c9b4c5 100644 --- a/resources/views/livewire/devices/configure.blade.php +++ b/resources/views/livewire/devices/configure.blade.php @@ -31,6 +31,10 @@ new class extends Component public $device_model_id; + public $is_mirror = false; + + public $mirror_device_id = null; + // Signal to device to use high compatibility approaches when redrawing content public $maximum_compatibility = false; @@ -98,6 +102,8 @@ new class extends Component $this->sleep_mode_from = optional($device->sleep_mode_from)->format('H:i'); $this->sleep_mode_to = optional($device->sleep_mode_to)->format('H:i'); $this->special_function = $device->special_function; + $this->is_mirror = $device->mirror_device_id !== null; + $this->mirror_device_id = $device->mirror_device_id; return view('livewire.devices.configure', [ 'image' => ($current_image_uuid) ? url($current_image_path) : null, @@ -145,6 +151,7 @@ new class extends Component 'rotate' => 'required|integer|min:0|max:359', 'image_format' => 'required|string', 'device_model_id' => 'nullable|exists:device_models,id', + 'mirror_device_id' => 'required_if:is_mirror,true', 'maximum_compatibility' => 'boolean', 'sleep_mode_enabled' => 'boolean', 'sleep_mode_from' => 'nullable|date_format:H:i', @@ -152,6 +159,13 @@ new class extends Component 'special_function' => 'nullable|string', ]); + if ($this->is_mirror) { + $mirrorDevice = auth()->user()->devices()->find($this->mirror_device_id); + abort_unless($mirrorDevice, 403, 'Invalid mirror device selected'); + abort_if($mirrorDevice->mirror_device_id !== null, 403, 'Cannot mirror a device that is already a mirror device'); + abort_if((int) $this->mirror_device_id === (int) $this->device->id, 403, 'Device cannot mirror itself'); + } + // Convert empty string to null for custom selection $deviceModelId = empty($this->device_model_id) ? null : $this->device_model_id; @@ -165,6 +179,7 @@ new class extends Component 'rotate' => $this->rotate, 'image_format' => $this->image_format, 'device_model_id' => $deviceModelId, + 'mirror_device_id' => $this->is_mirror ? $this->mirror_device_id : null, 'maximum_compatibility' => $this->maximum_compatibility, 'sleep_mode_enabled' => $this->sleep_mode_enabled, 'sleep_mode_from' => $this->sleep_mode_from, @@ -433,6 +448,18 @@ new class extends Component @endforeach + + @if($is_mirror) + + Select a device + @foreach(auth()->user()->devices->where('mirror_device_id', null)->where('id', '!=', $device->id) as $mirrorOption) + + {{ $mirrorOption->name }} ({{ $mirrorOption->friendly_id }}) + + @endforeach + + @endif + @if(empty($device_model_id)) diff --git a/tests/Feature/Devices/DeviceConfigureTest.php b/tests/Feature/Devices/DeviceConfigureTest.php index dff0954..bf4e19e 100644 --- a/tests/Feature/Devices/DeviceConfigureTest.php +++ b/tests/Feature/Devices/DeviceConfigureTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature; use App\Models\Device; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; +use Livewire\Livewire; use function Pest\Laravel\actingAs; @@ -23,3 +24,35 @@ test('configure view displays last_refreshed_at timestamp', function (): void { $response->assertOk() ->assertSee('5 minutes ago'); }); + +test('configure edit modal shows mirror checkbox and allows unchecking mirror', function (): void { + $user = User::factory()->create(); + actingAs($user); + + $deviceAttributes = [ + 'user_id' => $user->id, + 'width' => 800, + 'height' => 480, + 'rotate' => 0, + 'image_format' => 'png', + 'maximum_compatibility' => false, + ]; + $sourceDevice = Device::factory()->create($deviceAttributes); + $mirrorDevice = Device::factory()->create([ + ...$deviceAttributes, + 'mirror_device_id' => $sourceDevice->id, + ]); + + $response = $this->get(route('devices.configure', $mirrorDevice)); + $response->assertOk() + ->assertSee('Mirrors Device') + ->assertSee('Select Device to Mirror'); + + Livewire::test('devices.configure', ['device' => $mirrorDevice]) + ->set('is_mirror', false) + ->call('updateDevice') + ->assertHasNoErrors(); + + $mirrorDevice->refresh(); + expect($mirrorDevice->mirror_device_id)->toBeNull(); +});