clusev/resources/views/livewire/commands/index.blade.php

127 lines
7.2 KiB
PHP

@php
$field = 'w-full rounded-md border border-line bg-inset px-3 py-2 text-sm text-ink focus:border-accent/40 focus:outline-none';
$label = 'mb-1 block font-mono text-[11px] uppercase tracking-wider text-ink-3';
@endphp
<div class="space-y-5">
{{-- Header --}}
<div>
<p class="font-mono text-[11px] uppercase tracking-[0.2em] text-accent-text">{{ __('commands.eyebrow') }}</p>
<h2 class="mt-0.5 font-display text-xl font-semibold text-ink sm:text-2xl">{{ __('commands.title') }}</h2>
<p class="mt-1 text-sm text-ink-3">{{ __('commands.subtitle') }}</p>
</div>
{{-- Ad-hoc --}}
<x-panel :title="__('commands.adhoc_title')">
<form wire:submit="run" class="space-y-4">
<div>
<label class="{{ $label }}">{{ __('commands.command_label') }}</label>
<textarea wire:model="command" rows="2" class="{{ $field }} font-mono placeholder:text-ink-4" placeholder="{{ __('commands.command_placeholder') }}"></textarea>
@error('command') <p class="mt-1 flex items-center gap-1.5 font-mono text-[11px] text-offline"><x-icon name="alert" class="h-3.5 w-3.5 shrink-0" />{{ $message }}</p> @enderror
</div>
<div>
<label class="{{ $label }}">{{ __('commands.scope_label') }}</label>
<div class="flex flex-wrap gap-1.5">
@foreach (['all', 'group', 'servers'] as $s)
<button type="button" wire:click="$set('scopeType', '{{ $s }}')"
@class([
'inline-flex min-h-9 items-center rounded-md border px-3 text-xs transition-colors',
'border-accent/25 bg-accent/10 text-ink' => $scopeType === $s,
'border-line bg-inset text-ink-2 hover:bg-raised hover:text-ink' => $scopeType !== $s,
])>{{ __('commands.scope_'.$s) }}</button>
@endforeach
</div>
</div>
@if ($scopeType === 'group')
<div>
<label class="{{ $label }}">{{ __('commands.target_group_label') }}</label>
<select wire:model="scopeGroupUuid" class="{{ $field }}">
<option value=""></option>
@foreach ($groups as $g)
<option value="{{ $g->uuid }}">{{ $g->name }}</option>
@endforeach
</select>
</div>
@elseif ($scopeType === 'servers')
<div>
<label class="{{ $label }}">{{ __('commands.target_servers_label') }}</label>
<div class="grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3">
@foreach ($servers as $srv)
<label class="flex min-h-11 items-center gap-2.5 rounded-md border border-line bg-inset px-3 py-2 text-sm text-ink-2 transition-colors hover:bg-raised sm:min-h-0">
<input type="checkbox" value="{{ $srv->uuid }}" wire:model="selectedServers" class="h-4 w-4 shrink-0 rounded border-line bg-inset text-accent focus:ring-accent/40" />
<span class="min-w-0 truncate">{{ $srv->name }}</span>
</label>
@endforeach
</div>
</div>
@endif
<div class="flex justify-end">
<x-btn variant="primary" type="submit">
<x-icon name="command" class="h-3.5 w-3.5" /> {{ __('commands.run') }}
</x-btn>
</div>
</form>
</x-panel>
{{-- Results --}}
@if (! empty($results))
<x-panel :title="__('commands.results_title')" :padded="false">
<div class="divide-y divide-line">
@foreach ($results as $r)
<div wire:key="res-{{ $loop->index }}" class="px-4 py-3 sm:px-5">
<div class="flex items-center gap-2.5">
<x-status-dot :status="$r['ok'] ? 'online' : 'offline'" class="h-2.5 w-2.5" />
<span class="min-w-0 flex-1 truncate font-mono text-sm text-ink">{{ $r['server'] }}</span>
<x-status-pill :status="$r['ok'] ? 'online' : 'offline'">{{ $r['ok'] ? __('commands.exit_ok') : __('commands.exit_fail') }}</x-status-pill>
</div>
@if ($r['output'] !== '')
<pre class="mt-2 max-h-64 overflow-auto rounded-md border border-line bg-void p-3 font-mono text-[11px] leading-relaxed text-ink-2">{{ $r['output'] }}</pre>
@endif
</div>
@endforeach
</div>
</x-panel>
@endif
{{-- Runbooks --}}
<x-panel :title="__('commands.runbooks_title')" :padded="false">
@if ($runbooks->isEmpty())
<div class="px-4 py-6 text-center sm:px-5">
<p class="font-display text-sm font-semibold text-ink">{{ __('commands.no_runbooks_title') }}</p>
<p class="mt-1 text-xs text-ink-3">{{ __('commands.no_runbooks') }}</p>
</div>
@else
<div class="divide-y divide-line">
@foreach ($runbooks as $rb)
<div wire:key="rb-{{ $rb->uuid }}" class="flex flex-wrap items-center gap-3 px-4 py-3 sm:px-5">
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium text-ink">{{ $rb->name }}</p>
<p class="truncate font-mono text-[11px] text-ink-3">{{ $rb->command }}</p>
</div>
<x-btn variant="secondary" wire:click="runRunbook('{{ $rb->uuid }}')">{{ __('commands.run') }}</x-btn>
<x-modal-trigger variant="danger-soft" action="confirmDeleteRunbook('{{ $rb->uuid }}')">{{ __('common.delete') }}</x-modal-trigger>
</div>
@endforeach
</div>
@endif
<div class="border-t border-line p-4 sm:p-5">
<p class="{{ $label }}">{{ __('commands.new_runbook') }}</p>
<form wire:submit="createRunbook" class="grid gap-3 sm:grid-cols-[minmax(0,14rem)_minmax(0,1fr)_auto] sm:items-start">
<div>
<input wire:model="runbookName" type="text" maxlength="80" placeholder="{{ __('commands.runbook_name_label') }}" class="{{ $field }} placeholder:text-ink-4" />
@error('runbookName') <p class="mt-1 font-mono text-[11px] text-offline">{{ $message }}</p> @enderror
</div>
<div>
<input wire:model="runbookCommand" type="text" maxlength="4000" placeholder="{{ __('commands.runbook_command_label') }}" class="{{ $field }} font-mono placeholder:text-ink-4" />
@error('runbookCommand') <p class="mt-1 font-mono text-[11px] text-offline">{{ $message }}</p> @enderror
</div>
<x-btn variant="primary" type="submit">{{ __('commands.create') }}</x-btn>
</form>
</div>
</x-panel>
</div>