feat: Social page — aggregated post queues + X/video history (#345)

* feat(api): x/video post history endpoints

Approved or rejected drafts vanished from both queues permanently --
the listers exclude terminal statuses and no history surface existed,
so a posted tweet or video was only findable in the raw task list.
GET /x/posts/history and GET /video/posts/history (CEO-gated, bounded)
return acted-on drafts newest-first with the posted platform ids and
reject reasons from the draft markers. Route tests assert by identity,
not emptiness: approve/reject commits the whole session, so prior
tests' rows legitimately persist in the shared test DB.

* feat(panel): Social page aggregating post queues and history

New dashboard page composing the X and video post queues with one
unified history section beneath them -- both platforms interleaved
newest-first, kind and outcome badges, posted X ids linking to the
live tweet, reject reasons shown. The command center's two full queue
cards become a compact pending-counts card linking to the page, so the
queues have one home instead of duplicated surfaces.

---------

Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
Renzo F
2026-07-09 00:44:51 +02:00
committed by GitHub
co-authored by Renn F
parent 5886336259
commit f0b6390189
26 changed files with 1289 additions and 30 deletions
@@ -125,7 +125,8 @@ function XPostRow({
}
// CEO queue for held X drafts (release posts + mention replies). Hidden when
// empty (mirrors the release-proposal + playbook-review queues).
// empty (mirrors the release-proposal + playbook-review queues). Posted/
// rejected drafts move to the unified history on /social (SocialHistorySection).
export function XPostQueue({ className }: { className?: string }) {
const queryClient = useQueryClient();
const [rejecting, setRejecting] = useState<XPost | null>(null);
@@ -197,13 +198,12 @@ export function XPostQueue({ className }: { className?: string }) {
<Card className={className}>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Rocket className="h-5 w-5" />
X Post Queue
<Rocket className="h-5 w-5" />X Post Queue
</CardTitle>
<CardDescription>
Drafted release announcements, feature spotlights, and mention
replies (if enabled) land here for you to edit, approve, or
reject. Nothing posts on its own.
replies (if enabled) land here for you to edit, approve, or reject.
Nothing posts on its own.
</CardDescription>
</CardHeader>
<CardContent>
@@ -222,8 +222,7 @@ export function XPostQueue({ className }: { className?: string }) {
<Card className={className}>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Rocket className="h-5 w-5" />
X Post Queue
<Rocket className="h-5 w-5" />X Post Queue
<Badge variant="secondary">{posts.length}</Badge>
</CardTitle>
<CardDescription>