Refresh list status over Reverb with polling fallback, clarify queued vs processing, streamline upload empty states, and seed an admin login.
159 lines
4.1 KiB
PHP
159 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Recordings;
|
|
|
|
use App\Models\Recording;
|
|
use Flux\Flux;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\On;
|
|
use Livewire\Attributes\Title;
|
|
use Livewire\Attributes\Url;
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
|
|
#[Layout('layouts.app')]
|
|
#[Title('Recordings')]
|
|
class Index extends Component
|
|
{
|
|
use WithPagination;
|
|
|
|
public int $userId;
|
|
|
|
#[Url(as: 'q', history: true)]
|
|
public string $search = '';
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->userId = (int) Auth::id();
|
|
}
|
|
|
|
public function updatedSearch(): void
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
/**
|
|
* Re-render when any of this user's recordings broadcast a status change.
|
|
*/
|
|
#[On('echo-private:user.{userId}.recordings,.RecordingTranscriptionUpdated')]
|
|
public function onTranscriptionUpdated(): void
|
|
{
|
|
//
|
|
}
|
|
|
|
public function queuePending(): void
|
|
{
|
|
$queued = 0;
|
|
|
|
Auth::user()->recordings()
|
|
->whereIn('transcription_status', ['pending', 'failed', 'cancelled'])
|
|
->orderBy('id')
|
|
->each(function (Recording $recording) use (&$queued): void {
|
|
if ($recording->hasActiveTranscriptionJob()) {
|
|
return;
|
|
}
|
|
|
|
$recording->queueLocalTranscription();
|
|
$queued++;
|
|
});
|
|
|
|
if ($queued === 0) {
|
|
Flux::toast(text: 'No recordings need transcription right now.', variant: 'danger');
|
|
|
|
return;
|
|
}
|
|
|
|
Flux::toast(
|
|
text: $queued === 1
|
|
? 'Queued 1 recording for transcription.'
|
|
: "Queued {$queued} recordings for transcription.",
|
|
variant: 'success',
|
|
);
|
|
}
|
|
|
|
public function delete(int $recordingId): void
|
|
{
|
|
$recording = Auth::user()->recordings()->findOrFail($recordingId);
|
|
|
|
Gate::authorize('delete', $recording);
|
|
|
|
$recording->deleteFile();
|
|
$recording->delete();
|
|
|
|
Flux::toast(text: 'Recording deleted.', variant: 'success');
|
|
}
|
|
|
|
public function deleteAll(): void
|
|
{
|
|
$deleted = 0;
|
|
|
|
Auth::user()->recordings()
|
|
->orderBy('id')
|
|
->each(function (Recording $recording) use (&$deleted): void {
|
|
Gate::authorize('delete', $recording);
|
|
|
|
$recording->deleteFile();
|
|
$recording->delete();
|
|
$deleted++;
|
|
});
|
|
|
|
$this->resetPage();
|
|
|
|
if ($deleted === 0) {
|
|
Flux::toast(text: 'No recordings to delete.', variant: 'danger');
|
|
|
|
return;
|
|
}
|
|
|
|
Flux::toast(
|
|
text: $deleted === 1
|
|
? 'Deleted 1 recording.'
|
|
: "Deleted {$deleted} recordings.",
|
|
variant: 'success',
|
|
);
|
|
}
|
|
|
|
public function render(): View
|
|
{
|
|
$user = Auth::user();
|
|
|
|
$user->recordings()
|
|
->whereIn('transcription_status', ['pending', 'processing'])
|
|
->orderBy('id')
|
|
->each(fn (Recording $recording) => $recording->recoverOrphanedTranscription());
|
|
|
|
$totalCount = $user->recordings()->count();
|
|
|
|
$query = $user->recordings()->latest();
|
|
|
|
$search = trim($this->search);
|
|
|
|
if ($search !== '') {
|
|
$query->search($search);
|
|
}
|
|
|
|
$recordings = $query->paginate(20);
|
|
|
|
$pendingCount = $user->recordings()
|
|
->whereIn('transcription_status', ['pending', 'failed', 'cancelled'])
|
|
->get()
|
|
->filter(fn (Recording $recording) => ! $recording->hasActiveTranscriptionJob())
|
|
->count();
|
|
|
|
$hasActiveTranscriptions = $user->recordings()
|
|
->whereIn('transcription_status', ['pending', 'processing'])
|
|
->exists();
|
|
|
|
return view('livewire.recordings.index', [
|
|
'recordings' => $recordings,
|
|
'search' => $search,
|
|
'pendingCount' => $pendingCount,
|
|
'hasActiveTranscriptions' => $hasActiveTranscriptions,
|
|
'totalCount' => $totalCount,
|
|
]);
|
|
}
|
|
}
|