Add a Publisher abstraction and queued job to publish from the UI
Introduce Publisher/PublisherManager (WordPress + Reddit implementations) so publishing logic is shared between the CLI, the queue, and future network integrations. Add a "Publish" button on the Posts page that dispatches PublishPostJob instead of blocking the request — Reddit's publisher shells out to the existing Playwright sidecar and can take tens of seconds, so it can't run synchronously in a web request. Adds a `target` field (e.g. subreddit) and `publishing` status to Post, plus a `publish_error` field so failures surface in the UI. Refactors posts:publish to delegate to WordPressPublisher without changing its CLI output contract (existing tests pass unchanged). Also fixes two bugs found along the way: UpdatePostRequest was silently dropping `published_url` from PATCH requests (never in its validation rules, despite AI_API.md documenting it), and three Livewire index-page tests were broken by the earlier auth change (never re-run after adding the `auth` middleware) since they hit routes via HTTP without a logged-in user. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
<div>
|
||||
<div @if ($hasPublishing) wire:poll.3s @endif>
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h1 class="text-xl font-semibold">Posts</h1>
|
||||
<button wire:click="create" class="bg-blue-600 text-white px-4 py-2 rounded">Add Post</button>
|
||||
</div>
|
||||
|
||||
@if ($publishNotice)
|
||||
<div class="mb-4 p-3 bg-amber-50 border border-amber-200 text-amber-800 rounded text-sm">{{ $publishNotice }}</div>
|
||||
@endif
|
||||
|
||||
<table class="w-full bg-white border border-gray-200 rounded">
|
||||
<thead>
|
||||
<tr class="text-left border-b border-gray-200">
|
||||
@@ -22,10 +26,22 @@
|
||||
<td class="p-3">{{ $post->site->name }}</td>
|
||||
<td class="p-3">{{ ucfirst($post->type) }}</td>
|
||||
<td class="p-3">{{ $post->title ?: \Illuminate\Support\Str::limit($post->body, 40) }}</td>
|
||||
<td class="p-3">{{ ucfirst($post->status) }}</td>
|
||||
<td class="p-3">
|
||||
@if ($post->status === 'published' && $post->published_url)
|
||||
<a href="{{ $post->published_url }}" target="_blank" class="text-green-700 hover:underline">Published</a>
|
||||
@else
|
||||
{{ ucfirst($post->status) }}
|
||||
@endif
|
||||
@if ($post->status === 'failed' && $post->publish_error)
|
||||
<div class="text-xs text-red-600 mt-0.5">{{ $post->publish_error }}</div>
|
||||
@endif
|
||||
</td>
|
||||
<td class="p-3">{{ $post->scheduled_at?->format('Y-m-d H:i') ?? '—' }}</td>
|
||||
<td class="p-3">{{ $post->socialAccount?->username ?? '—' }}</td>
|
||||
<td class="p-3 text-right space-x-2">
|
||||
@if (in_array($post->type, ['blog', 'reddit']) && in_array($post->status, ['draft', 'scheduled', 'failed']))
|
||||
<button wire:click="publish({{ $post->id }})" class="text-green-700">Publish</button>
|
||||
@endif
|
||||
<button wire:click="edit({{ $post->id }})" class="text-blue-600">Edit</button>
|
||||
<button wire:click="delete({{ $post->id }})" wire:confirm="Delete this post?" class="text-red-600">Delete</button>
|
||||
</td>
|
||||
@@ -84,6 +100,12 @@
|
||||
@error('body') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium">Target (optional — e.g. subreddit for Reddit posts)</label>
|
||||
<input type="text" wire:model="target" class="w-full border rounded p-2">
|
||||
@error('target') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium">Status</label>
|
||||
<select wire:model="status" class="w-full border rounded p-2">
|
||||
|
||||
Reference in New Issue
Block a user