Podcast workflow: assign lanes by hand, match by season, unique keys for unseasoned episodes; drop old checklist data file; v2.16.0

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-12 08:25:00 -04:00
1 parent ac1b06f945
commit 900a3efee3
6 files changed
+69 -698

No files matched your search

+21 -2
View File
@@ -1816,6 +1816,7 @@ interface PodcastWorkflowItem {
episodeNumber: string
title: string
lane: 'A' | 'B' | 'other'
laneOverride?: '' | 'A' | 'B' | 'other'
released: boolean
releaseDate?: string
spotifyUrl?: string
@@ -1874,7 +1875,7 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string; season
const r = await fetch('/api/admin/podcast-workflow/planned', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ season: laneSeason ? String(laneSeason) : '', episodeNumber: newNumber, title: newTitle }),
body: JSON.stringify({ season: laneSeason ? String(laneSeason) : '', episodeNumber: newNumber, title: newTitle, lane }),
})
const d = await r.json()
if (!r.ok) { setError(d.message ?? 'Could not add episode.'); return }
@@ -1882,6 +1883,15 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string; season
await reload()
setSelectedKey(d.key)
}
const setLaneFor = async (key: string, value: string) => {
await fetch(`/api/admin/podcast-workflow/${encodeURIComponent(key)}/lane`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ lane: value }),
})
setSelectedKey('')
reload()
}
const removePlanned = async (key: string) => {
if (!confirm('Remove this planned episode and its progress?')) return
await fetch(`/api/admin/podcast-workflow/planned/${encodeURIComponent(key)}`, { method: 'DELETE' })
@@ -1932,7 +1942,7 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string; season
)}
</div>
{lane !== 'other' && !laneSeason && (
<p className="admin-stats-note">Set this lane’s Podcast Season Number in Current Series so its episodes can be matched.</p>
<p className="admin-stats-note">Set this lane’s Podcast Season Number in Current Series to match episodes automatically, or assign episodes to this lane by hand.</p>
)}
{loading ? <p className="admin-stats-note">Loading…</p> : (
@@ -1970,6 +1980,15 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string; season
{selected.hasScript ? 'Script uploaded.' : 'No script yet.'} This moves to Released on its own once it shows up in the feed.
</p>
)}
<div className="admin-field" style={{ maxWidth: 360, margin: '8px 0 12px' }}>
<label htmlFor="pw-lane">Lane</label>
<select id="pw-lane" value={selected.laneOverride || 'auto'} onChange={e => setLaneFor(selected.key, e.target.value)}>
<option value="auto">Automatic (by season number{selected.season ? ` ${selected.season}` : ''})</option>
<option value="A">Lane A — {laneA.title || 'Primary series'}</option>
<option value="B">Lane B — {laneB.title || 'Second series'}</option>
<option value="other">Other</option>
</select>
</div>
<ol style={{ paddingLeft: 0, listStyle: 'none', margin: 0 }}>
{PODCAST_STEP_DEFS.map((s, idx) => {
const completedAt = selected.state.steps[s.key]