Add sortable columns with a fixed status width, and keep the show page in sync via Echo, polling, and Alpine hydrate while transcription runs.
94 lines
2.4 KiB
PHP
94 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Recordings;
|
|
|
|
use App\Models\Recording;
|
|
use Flux\Flux;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\On;
|
|
use Livewire\Component;
|
|
|
|
#[Layout('layouts.app')]
|
|
class Show extends Component
|
|
{
|
|
public Recording $recording;
|
|
|
|
public int $userId;
|
|
|
|
public function mount(Recording $recording): void
|
|
{
|
|
Gate::authorize('view', $recording);
|
|
|
|
$recording->recoverOrphanedTranscription();
|
|
$recording->refresh();
|
|
|
|
$this->recording = $recording;
|
|
$this->userId = (int) $recording->user_id;
|
|
}
|
|
|
|
/**
|
|
* Re-render when this recording broadcasts a status change (same channel as the index).
|
|
*
|
|
* @param array<string, mixed> $event
|
|
*/
|
|
#[On('echo-private:user.{userId}.recordings,.RecordingTranscriptionUpdated')]
|
|
public function onTranscriptionUpdated(array $event = []): void
|
|
{
|
|
if (isset($event['id']) && (int) $event['id'] !== (int) $this->recording->id) {
|
|
return;
|
|
}
|
|
|
|
$this->recording->refresh();
|
|
}
|
|
|
|
public function startTranscription(): void
|
|
{
|
|
Gate::authorize('transcribe', $this->recording);
|
|
|
|
$this->recording->queueLocalTranscription();
|
|
$this->recording->refresh();
|
|
|
|
Flux::toast(text: 'Transcription started. Progress updates below.', variant: 'success');
|
|
}
|
|
|
|
public function cancelTranscription(): void
|
|
{
|
|
Gate::authorize('transcribe', $this->recording);
|
|
|
|
if (! $this->recording->isTranscribing()) {
|
|
Flux::toast(text: 'No transcription is currently running.', variant: 'danger');
|
|
|
|
return;
|
|
}
|
|
|
|
$this->recording->cancelTranscription();
|
|
$this->recording->refresh();
|
|
|
|
Flux::toast(text: 'Transcription stopped.', variant: 'success');
|
|
}
|
|
|
|
public function delete(): mixed
|
|
{
|
|
Gate::authorize('delete', $this->recording);
|
|
|
|
$this->recording->deleteFile();
|
|
$this->recording->delete();
|
|
|
|
session()->flash('success', 'Recording deleted.');
|
|
|
|
return $this->redirect(route('recordings.index'), navigate: true);
|
|
}
|
|
|
|
public function render(): View
|
|
{
|
|
if ($this->recording->isTranscribing()) {
|
|
$this->recording->refresh();
|
|
}
|
|
|
|
return view('livewire.recordings.show')
|
|
->title($this->recording->title);
|
|
}
|
|
}
|