152 lines
10 KiB
PHP
152 lines
10 KiB
PHP
<div>
|
|
<x-topbar :title="$device->name" :subtitle="$device->model">
|
|
<x-slot:actions>
|
|
<a href="{{ route('devices.index') }}" wire:navigate
|
|
class="inline-flex items-center gap-1.5 rounded-lg border border-line-soft bg-raised px-2.5 py-1.5 text-[12px] font-semibold text-ink-2 hover:text-ink transition-colors">
|
|
<x-icon name="chevron" :size="14" class="rotate-180" />
|
|
<span class="hidden sm:inline">{{ __('nav.devices') }}</span>
|
|
</a>
|
|
</x-slot:actions>
|
|
</x-topbar>
|
|
|
|
<div class="px-5 lg:px-[26px] py-6 flex flex-col gap-5 max-w-[1560px] mx-auto w-full">
|
|
@if ($flash)
|
|
<div @class([
|
|
'flex items-center gap-3 rounded-card border border-line-soft px-4 py-3',
|
|
'bg-online/10' => $flashOk,
|
|
'bg-offline/10' => ! $flashOk,
|
|
])>
|
|
<x-icon :name="$flashOk ? 'check' : 'alert'" :size="17" @class(['shrink-0', 'text-online' => $flashOk, 'text-offline' => ! $flashOk]) />
|
|
<span class="text-[13px] text-ink">{{ $flash }}</span>
|
|
<button type="button" wire:click="$set('flash', null)" class="ml-auto text-ink-3 hover:text-ink">
|
|
<x-icon name="close" :size="16" />
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($mqttCredential)
|
|
<div class="rounded-card border border-accent/30 bg-accent/10 p-4 flex flex-col gap-2">
|
|
<div class="flex items-center gap-2 text-[13px] font-bold text-ink"><x-icon name="lock" :size="16" class="text-accent" /> {{ __('devices.mqtt_credential_title') }}</div>
|
|
<p class="text-[12px] text-ink-2 max-w-2xl">{{ __('devices.mqtt_credential_hint') }}</p>
|
|
<dl class="grid grid-cols-2 sm:grid-cols-3 gap-x-4 gap-y-2 mt-1">
|
|
<x-detail :label="__('devices.mqtt_username')" mono>{{ $mqttCredential['username'] }}</x-detail>
|
|
<x-detail :label="__('devices.mqtt_password')" mono>{{ $mqttCredential['password'] }}</x-detail>
|
|
<x-detail label="Port" mono>{{ $mqttCredential['port'] }}</x-detail>
|
|
</dl>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-[1fr_340px] gap-5 items-start">
|
|
{{-- main --}}
|
|
<div class="flex flex-col gap-5">
|
|
{{-- identity + name edit --}}
|
|
<x-panel :title="__('devices.device')">
|
|
<div class="flex flex-col gap-4">
|
|
<div class="flex items-center gap-3">
|
|
<x-status-dot :state="$device->isOnline() ? 'online' : 'offline'" :pulse="$device->isOnline()" />
|
|
<x-status-pill :state="$device->isOnline() ? 'online' : 'offline'">
|
|
{{ $device->isOnline() ? __('devices.online') : __('devices.offline') }}
|
|
</x-status-pill>
|
|
@if ($device->status !== 'active')
|
|
<x-status-pill state="neutral">{{ __('devices.status_'.$device->status) }}</x-status-pill>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex flex-col gap-1.5">
|
|
<label for="name" class="text-[12px] font-semibold text-ink-2">{{ __('devices.name') }}</label>
|
|
<div class="flex gap-2">
|
|
<input wire:model="name" id="name" type="text"
|
|
class="flex-1 rounded-lg bg-raised border border-line px-3 py-2.5 text-sm text-ink outline-none transition-colors focus:border-accent focus:ring-1 focus:ring-accent">
|
|
<button type="button" wire:click="saveName"
|
|
class="rounded-lg bg-accent px-4 py-2.5 text-sm font-bold text-base transition-[filter] hover:brightness-110">
|
|
{{ __('devices.save') }}
|
|
</button>
|
|
</div>
|
|
@error('name') <p class="text-[12px] text-offline">{{ $message }}</p> @enderror
|
|
</div>
|
|
|
|
<dl class="grid grid-cols-2 sm:grid-cols-3 gap-x-4 gap-y-3 pt-1">
|
|
<x-detail :label="__('devices.vendor')">{{ $device->vendor ?? '—' }}</x-detail>
|
|
<x-detail :label="__('devices.model')">{{ $device->model ?? '—' }}</x-detail>
|
|
<x-detail :label="__('devices.protocol')" mono>{{ $device->protocol ?? '—' }}</x-detail>
|
|
<x-detail :label="__('devices.room')">{{ $device->room?->name ?? '—' }}</x-detail>
|
|
<x-detail :label="__('devices.last_seen')" mono>{{ $device->last_seen_at?->diffForHumans() ?? '—' }}</x-detail>
|
|
<x-detail :label="__('devices.uuid')" mono>{{ \Illuminate\Support\Str::limit($device->uuid, 13, '…') }}</x-detail>
|
|
</dl>
|
|
</div>
|
|
</x-panel>
|
|
|
|
{{-- capabilities / entities --}}
|
|
<x-panel :title="__('devices.capabilities')">
|
|
@if ($device->entities->isEmpty())
|
|
<p class="text-[13px] text-ink-3">{{ __('devices.no_capabilities') }}</p>
|
|
@else
|
|
<div class="flex flex-col divide-y divide-line-soft -my-1">
|
|
@foreach ($device->entities as $entity)
|
|
<div class="flex items-center gap-3 py-3 first:pt-1 last:pb-1">
|
|
<span class="text-[13px] font-semibold text-ink">{{ $entity->name ?? $entity->key }}</span>
|
|
<span class="text-[11px] font-mono text-ink-3">{{ $entity->type }}</span>
|
|
<div class="ml-auto flex items-center gap-3">
|
|
<x-entity-state :entity="$entity" />
|
|
@if (in_array($entity->type, ['switch', 'light']))
|
|
<x-toggle :on="(bool) data_get($entity->state?->state, 'on', false)"
|
|
wire:click="toggleEntity({{ $entity->id }})" :label="$entity->name ?? $entity->key" />
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</x-panel>
|
|
</div>
|
|
|
|
{{-- rail: actions + settings --}}
|
|
<div class="flex flex-col gap-5">
|
|
<x-panel :title="__('devices.actions')">
|
|
<div class="flex flex-col gap-2">
|
|
<button type="button"
|
|
wire:click="$dispatch('openModal', { component: 'modals.confirm', arguments: { title: @js(__('devices.restart_confirm_title')), body: @js(__('devices.restart_confirm_body', ['name' => $device->name])), confirmLabel: @js(__('devices.restart')), event: 'restartDevice', to: 'devices.show', danger: true } })"
|
|
class="flex items-center gap-2.5 rounded-lg border border-line-soft bg-raised px-3 py-2.5 text-[13px] font-semibold text-ink hover:border-line transition-colors">
|
|
<x-icon name="activity" :size="16" class="text-ink-2" /> {{ __('devices.restart') }}
|
|
</button>
|
|
<button type="button" wire:click="checkUpdate"
|
|
class="flex items-center gap-2.5 rounded-lg border border-line-soft bg-raised px-3 py-2.5 text-[13px] font-semibold text-ink hover:border-line transition-colors">
|
|
<x-icon name="wifi" :size="16" class="text-ink-2" /> {{ __('devices.check_update') }}
|
|
</button>
|
|
</div>
|
|
<p class="mt-3 text-[11.5px] text-ink-3">{{ __('devices.actions_demo_hint') }}</p>
|
|
</x-panel>
|
|
|
|
<x-panel :title="__('devices.settings')">
|
|
<div class="flex flex-col gap-4">
|
|
<div class="flex flex-col gap-1.5">
|
|
<label for="room" class="text-[12px] font-semibold text-ink-2">{{ __('devices.room') }}</label>
|
|
<div class="flex gap-2">
|
|
<select wire:model="roomId" id="room"
|
|
class="flex-1 rounded-lg bg-raised border border-line px-3 py-2.5 text-sm text-ink outline-none focus:border-accent focus:ring-1 focus:ring-accent">
|
|
<option value="">{{ __('devices.no_room') }}</option>
|
|
@foreach ($rooms as $room)
|
|
<option value="{{ $room->id }}">{{ $room->name }}</option>
|
|
@endforeach
|
|
</select>
|
|
<button type="button" wire:click="saveRoom"
|
|
class="rounded-lg border border-line px-3.5 py-2.5 text-[13px] font-semibold text-ink-2 hover:text-ink hover:bg-raised transition-colors">
|
|
{{ __('devices.save') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3 border-t border-line-soft pt-3">
|
|
<div class="min-w-0">
|
|
<div class="text-[13px] font-semibold text-ink">{{ __('devices.active') }}</div>
|
|
<div class="text-[11.5px] text-ink-3">{{ __('devices.active_hint') }}</div>
|
|
</div>
|
|
<x-toggle :on="$device->status === 'active'" wire:click="toggleStatus" :label="__('devices.active')" class="ml-auto" />
|
|
</div>
|
|
</div>
|
|
</x-panel>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|