mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-14 07:27:47 +00:00
add features
* feat: autojoin toggle * feat: auto add devices * feat: proxy feature * feat: support puppeteer in docker * feat: toggle to activate cloud proxy * feat: relay device information * feat: relay logs to cloud * feat: migrate on start * feat: calculate battery state, wifi signal * feat: eye candy for configure view * feat: update via api
This commit is contained in:
parent
d4eb832186
commit
715e6a2562
53 changed files with 1459 additions and 460 deletions
120
resources/views/livewire/devices/configure.blade.php
Normal file
120
resources/views/livewire/devices/configure.blade.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
new class extends Component {
|
||||
|
||||
public $device;
|
||||
|
||||
public function mount(\App\Models\Device $device)
|
||||
{
|
||||
abort_unless(auth()->user()->devices->contains($device), 403);
|
||||
|
||||
$current_image_uuid = $device->current_screen_image;
|
||||
$current_image_path = 'images/generated/' . $current_image_uuid . '.png';
|
||||
|
||||
return view('livewire.devices.configure', compact('device'), [
|
||||
'image' => ($current_image_uuid) ? url($current_image_path) : null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteDevice(\App\Models\Device $device)
|
||||
{
|
||||
abort_unless(auth()->user()->devices->contains($device), 403);
|
||||
$device->delete();
|
||||
|
||||
redirect()->route('devices');
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="bg-muted flex flex-col items-center justify-center gap-6 p-6 md:p-10">
|
||||
<div class="flex flex-col gap-6">
|
||||
<div
|
||||
class="rounded-xl border bg-white dark:bg-stone-950 dark:border-stone-800 text-stone-800 shadow-xs">
|
||||
<div class="px-10 py-8 min-w-lg">
|
||||
@php
|
||||
$current_image_uuid =$device->current_screen_image;
|
||||
file_exists('storage/images/generated/' . $current_image_uuid . '.png') ? $file_extension = 'png' : $file_extension = 'bmp';
|
||||
$current_image_path = 'storage/images/generated/' . $current_image_uuid . '.' . $file_extension;
|
||||
@endphp
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<flux:tooltip content="Friendly ID: {{$device->friendly_id}}" position="bottom">
|
||||
<h1 class="text-xl font-medium dark:text-zinc-200">{{ $device->name }}</h1>
|
||||
</flux:tooltip>
|
||||
<div>
|
||||
<flux:modal.trigger name="edit-device">
|
||||
<flux:button icon="key" variant="subtle"/>
|
||||
</flux:modal.trigger>
|
||||
<flux:modal.trigger name="delete-device">
|
||||
<flux:button icon="trash" variant="danger"/>
|
||||
</flux:modal.trigger>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<flux:tooltip content="Last update" position="bottom">
|
||||
<span class="dark:text-zinc-200">{{$device->updated_at->diffForHumans()}}</span>
|
||||
</flux:tooltip>
|
||||
<flux:separator vertical/>
|
||||
<flux:tooltip content="MAC Address" position="bottom">
|
||||
<span class="dark:text-zinc-200">{{$device->mac_address}}</span>
|
||||
</flux:tooltip>
|
||||
<flux:separator vertical/>
|
||||
<flux:tooltip content="Firmware Version" position="bottom">
|
||||
<span class="dark:text-zinc-200">{{$device->last_firmware_version}}</span>
|
||||
</flux:tooltip>
|
||||
<flux:separator vertical/>
|
||||
<x-responsive-icons.wifi :strength="$device->wifiStrengh" :rssi="$device->last_rssi_level"
|
||||
class="dark:text-zinc-200"/>
|
||||
<flux:separator vertical/>
|
||||
<x-responsive-icons.battery :percent="$device->batteryPercent"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<flux:modal name="edit-device" class="md:w-96">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
{{-- <flux:heading size="lg">Edit TRMNL</flux:heading>--}}
|
||||
{{-- <flux:subheading></flux:subheading>--}}
|
||||
</div>
|
||||
|
||||
{{-- <flux:input label="Name" value="{{ $device->name }}"/>--}}
|
||||
|
||||
<flux:input label="API Key" icon="key" value="{{ $device->api_key }}" type="password"
|
||||
viewable class="max-w-xs"/>
|
||||
|
||||
|
||||
<div class="flex">
|
||||
<flux:spacer/>
|
||||
|
||||
{{-- <flux:button type="submit" variant="primary">Save changes</flux:button>--}}
|
||||
</div>
|
||||
</div>
|
||||
</flux:modal>
|
||||
|
||||
<flux:modal name="delete-device" class="min-w-[22rem] space-y-6">
|
||||
<div>
|
||||
<flux:heading size="lg">Delete {{$device->name}}?</flux:heading>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<flux:spacer/>
|
||||
|
||||
<flux:modal.close>
|
||||
<flux:button variant="ghost">Cancel</flux:button>
|
||||
</flux:modal.close>
|
||||
<flux:button wire:click="deleteDevice({{ $device->id }})" variant="danger">Delete device</flux:button>
|
||||
</div>
|
||||
</flux:modal>
|
||||
|
||||
|
||||
@if($current_image_uuid)
|
||||
<flux:separator class="mt-6 mb-6" text="Next Screen"/>
|
||||
<img src="{{ asset($current_image_path) }}" alt="Next Image"/>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
205
resources/views/livewire/devices/manage.blade.php
Normal file
205
resources/views/livewire/devices/manage.blade.php
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Device;
|
||||
use Livewire\Volt\Component;
|
||||
|
||||
new class extends Component {
|
||||
|
||||
public $devices;
|
||||
|
||||
public $showDeviceForm = false;
|
||||
|
||||
public $name;
|
||||
|
||||
public $mac_address;
|
||||
|
||||
public $api_key;
|
||||
|
||||
public $default_refresh_interval = 900;
|
||||
|
||||
public $friendly_id;
|
||||
|
||||
protected $rules = [
|
||||
'mac_address' => 'required',
|
||||
'api_key' => 'required',
|
||||
'default_refresh_interval' => 'required|integer',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->devices = auth()->user()->devices;
|
||||
return view('livewire.devices.manage');
|
||||
}
|
||||
|
||||
public function createDevice(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
Device::create([
|
||||
'name' => $this->name,
|
||||
'mac_address' => $this->mac_address,
|
||||
'api_key' => $this->api_key,
|
||||
'default_refresh_interval' => $this->default_refresh_interval,
|
||||
'friendly_id' => $this->friendly_id,
|
||||
'user_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
$this->reset();
|
||||
\Flux::modal('create-device')->close();
|
||||
|
||||
$this->devices = auth()->user()->devices;
|
||||
session()->flash('message', 'Device created successfully.');
|
||||
}
|
||||
|
||||
public function toggleProxyCloud(Device $device): void
|
||||
{
|
||||
abort_unless(auth()->user()->devices->contains($device), 403);
|
||||
$device->update([
|
||||
'proxy_cloud' => !$device->proxy_cloud,
|
||||
]);
|
||||
|
||||
// if ($device->proxy_cloud) {
|
||||
// \App\Jobs\FetchProxyCloudResponses::dispatch();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div>
|
||||
<div class="py-12">
|
||||
{{--@dump($devices)--}}
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-semibold dark:text-gray-100">Devices</h2>
|
||||
<flux:modal.trigger name="create-device">
|
||||
<flux:button icon="plus" variant="primary">Add Device</flux:button>
|
||||
</flux:modal.trigger>
|
||||
</div>
|
||||
@if (session()->has('message'))
|
||||
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4">
|
||||
{{ session('message') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<flux:modal name="create-device" class="md:w-96">
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<flux:heading size="lg">Add Device</flux:heading>
|
||||
</div>
|
||||
|
||||
<form wire:submit="createDevice">
|
||||
<div class="mb-4">
|
||||
<flux:input label="Name" wire:model="name" id="name" class="block mt-1 w-full" type="text"
|
||||
name="name"
|
||||
autofocus/>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<flux:input label="Mac Address" wire:model="mac_address" id="mac_address"
|
||||
class="block mt-1 w-full"
|
||||
type="text" name="mac_address" autofocus/>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<flux:input label="API Key" wire:model="api_key" id="api_key" class="block mt-1 w-full"
|
||||
type="text"
|
||||
name="api_key" autofocus/>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<flux:input label="Friendly Id" wire:model="friendly_id" id="friendly_id"
|
||||
class="block mt-1 w-full"
|
||||
type="text" name="friendly_id" autofocus/>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<flux:input label="Refresh Rate (seconds)" wire:model="default_refresh_interval"
|
||||
id="default_refresh_interval"
|
||||
class="block mt-1 w-full" type="text" name="default_refresh_interval"
|
||||
autofocus/>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<flux:spacer/>
|
||||
<flux:button type="submit" variant="primary">Create Device</flux:button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</flux:modal>
|
||||
|
||||
<table
|
||||
class="min-w-full table-fixed text-zinc-800 divide-y divide-zinc-800/10 dark:divide-white/20 text-zinc-800"
|
||||
data-flux-table="">
|
||||
<thead data-flux-columns="">
|
||||
<tr>
|
||||
<th class="py-3 px-3 first:pl-0 last:pr-0 text-left text-sm font-medium text-zinc-800 dark:text-white"
|
||||
data-flux-column="">
|
||||
<div class="whitespace-nowrap flex group-[]/right-align:justify-end">Name</div>
|
||||
</th>
|
||||
<th class="py-3 px-3 first:pl-0 last:pr-0 text-left text-sm font-medium text-zinc-800 dark:text-white"
|
||||
data-flux-column="">
|
||||
<div class="whitespace-nowrap flex group-[]/right-align:justify-end">Friendly ID</div>
|
||||
</th>
|
||||
<th class="py-3 px-3 first:pl-0 last:pr-0 text-left text-sm font-medium text-zinc-800 dark:text-white"
|
||||
data-flux-column="">
|
||||
<div class="whitespace-nowrap flex group-[]/right-align:justify-end">Mac Address</div>
|
||||
</th>
|
||||
<th class="py-3 px-3 first:pl-0 last:pr-0 text-left text-sm font-medium text-zinc-800 dark:text-white"
|
||||
data-flux-column="">
|
||||
<div class="whitespace-nowrap flex group-[]/right-align:justify-end">Refresh</div>
|
||||
</th>
|
||||
<th class="py-3 px-3 first:pl-0 last:pr-0 text-left text-sm font-medium text-zinc-800 dark:text-white"
|
||||
data-flux-column="">
|
||||
<div class="whitespace-nowrap flex group-[]/right-align:justify-end">Actions</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-zinc-800/10 dark:divide-white/20" data-flux-rows="">
|
||||
@foreach ($devices as $device)
|
||||
<tr data-flux-row="">
|
||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300"
|
||||
>
|
||||
{{ $device->name }}
|
||||
</td>
|
||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300"
|
||||
>
|
||||
{{ $device->friendly_id }}
|
||||
</td>
|
||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300"
|
||||
>
|
||||
<div type="button" data-flux-badge="data-flux-badge"
|
||||
class="inline-flex items-center font-medium whitespace-nowrap -mt-1 -mb-1 text-xs py-1 [&_[data-flux-badge-icon]]:size-3 [&_[data-flux-badge-icon]]:mr-1 rounded-md px-2 text-zinc-700 [&_button]:!text-zinc-700 dark:text-zinc-200 [&_button]:dark:!text-zinc-200 bg-zinc-400/15 dark:bg-zinc-400/40 [&:is(button)]:hover:bg-zinc-400/25 [&:is(button)]:hover:dark:bg-zinc-400/50">
|
||||
{{ $device->mac_address }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap text-zinc-500 dark:text-zinc-300"
|
||||
>
|
||||
{{ $device->default_refresh_interval }}
|
||||
</td>
|
||||
<td class="py-3 px-3 first:pl-0 last:pr-0 text-sm whitespace-nowrap font-medium text-zinc-800 dark:text-white"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<flux:button href="{{ route('devices.configure', $device) }}" wire:navigate icon="eye">
|
||||
</flux:button>
|
||||
|
||||
<flux:tooltip
|
||||
content="Proxies images from the TRMNL Cloud service when no image is set (available in TRMNL DEV Edition only)."
|
||||
position="bottom">
|
||||
<flux:switch wire:model.live="proxy_cloud"
|
||||
wire:click="toggleProxyCloud({{ $device->id }})"
|
||||
:checked="$device->proxy_cloud" label="☁️ Proxy"/>
|
||||
</flux:tooltip>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
<!--[if ENDBLOCK]><![endif]-->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue