feat(blog): post publish toggle + status filter on the posts list - #6360
Merged
Conversation
Adds a status header row at the top of the post Settings tab: a badge showing the current state plus a button that flips `status` between "published" and "draft". The write goes through the existing autosave, so no new save path. An unset `status` reads as published — the field is new and optional, so every pre-existing post would otherwise read as a draft. Statuses the editor does not own (generating, awaiting_review) render verbatim instead of being reported as drafts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
guitavano
approved these changes
Aug 20, 2026
Label + badge + button said the same thing three times. Collapsed to the Label + Switch pattern SeoFields already uses two fields below, dropping PostStatusBadge and three of the four i18n keys with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The switch now paints bg-success when checked, so "published" reads at a glance instead of looking like every other toggle. Adds Published/Draft to the posts list filter dropdown, alongside the existing category and author groups (same one-filter-at-a-time radio, so status does not stack with a category). Counts come from the same live scan the other groups use, and the filter resets with them on collection switch and on the "Manage posts" landing. Both surfaces read isPostPublished() in blog-data, so the list and the editor can't disagree about what "published" means: unset status is published (the field postdates existing posts), everything else — draft, generating, awaiting_review — is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
decocms Bot
pushed a commit
that referenced
this pull request
Aug 20, 2026
PR: #6360 feat(blog): post publish toggle + status filter on the posts list Bump type: minor - decocms (apps/api/package.json): 4.250.0 -> 4.251.0 - @decocms/native (apps/native/package.json): 4.250.0 -> 4.251.0 Deploy-Scope: web
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Integrates the blog app's new optional
statusfield into the CMS. Only thepublished⇄drafttransition is exposed — the other states (archived,generating,awaiting_review) are read, never written.Editor (Settings tab, top-right). A
Publishedswitch, styledbg-successwhen on. Flipping it writesstatus: "published" | "draft"onto the post payload; the existing autosave persists it. No new save path, no new tool.Posts list.
Published/Draftjoin the existing filter dropdown as a third group next to Category and Author, with live counts like the other two. It resets alongside the other post filters on collection switch and on the "Manage posts" landing, and clearing selection behaves as before.Assumption worth reviewing
An unset
statusreads as published, centralized inisPostPublished()(blog-data.ts) and used by both the editor switch and the list filter so the two can never disagree. The field is new and optional, so every post that predates it has nostatus— treating that as a draft would show the whole existing blog as unpublished.This holds as long as the blog app filters with
status !== "draft". If the app filters withstatus === "published", it needs the same undefined-is-published default, otherwise the site and the CMS disagree about legacy posts.Everything that is not
published(includinggenerating/awaiting_review) groups under Draft in the filter and reads as off in the switch — flipping the switch overwrites such a state with an explicitdraft/published.emptyBlogPayloadis untouched, so a new post has nostatusand therefore reads as published. Making new posts draft-by-default is a one-liner if preferred.Known limitation
The filter dropdown is a single radio group by existing design ("one filter at a time"), so status does not stack with category/author — you can't ask for "drafts in Sustentabilidade". Making status an orthogonal second chip is a contained follow-up if that combination is wanted.
Testing
bun test apps/web/src/components/sandbox/content/blog/— 125 pass, 0 fail. New unit tests coverisPostPublished(unset / empty / non-string / exact-match / case + whitespace sensitivity / the non-editable states) andlistPostsWithMetareportingpublished; the existinglistPostsWithMetaassertion was updated for the new field.bun --bun node_modules/typescript/bin/tsc --noEmit -p apps/web/tsconfig.json— exit 0bun run lint— 18 warnings, 0 errors; identical to the count on a stashed tree, so nothing newbun run fmt— cleanNot verified in a running browser: the exact rendering of the green switch and the dropdown group. Both are token-based (
bg-success) and reuse the existingDropdownMenuRadioItem+OptionCountmarkup.Affected areas
apps/webblog post editor and posts list only. i18n keys added to bothen/sandbox.tsandpt-br/sandbox.ts.🤖 Generated with Claude Code