Replace the per-page Publish with one Publish for all pending changes #156
Labels
No labels
bug
enhancement
needs-triage
ready-for-agent
ready-for-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle#156
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Remove the per-page Publish and keep one Publish: today's "Publish all" in the app header, renamed. It publishes every pending change, as Publish all does now. More and more single editor actions change several pages at once. Renaming a page rewrites links to it on other pages, and renaming or deleting a category rewrites every page that uses it (#152). Publishing one page at a time leaves the rest of such a change unpublished.
The draft-link warning, which today only the per-page publish runs, moves to the one Publish, narrowed to links to disabled pages.
Current behavior
published(PublishButtoninweb/src/components/PageEditorChrome.tsx, used byPagePaneandEntryEditor).POST /api/page/publish {page, lang, force?}:main;forceis set, first scans the page for links to pages that would 404 on the live site: disabled pages (front-matterdraft), and never-published pages that this publish does not carry. If it finds any, it answers{"warning":{"draftLinks":[…]}}and publishes nothing. The editor shows "Linked pages are unpublished" with Cancel and "Publish anyway", which posts again withforce. The scan is best-effort: it reads markdown link destinations, inline<a href>and link-typed element params, and matches them by content path and default pretty URL.forceincluded) sit under the page's toolbar; a failed pre-flight opens a build-failed dialog.App.tsx).POST /api/publish-all {lang}publishes every pending change undercontent/andassets/media/in one commit, answers empty when nothing is pending, and never scans links. Its chip, error strip (with Retry) and build-failed dialog belong to the header.mainplus the publish's paths, refuses when a page in the export would reference a library filemainwould not have, and builds with the pinned Hugo. A failure answers 422 and nothing is committed./api/publish-all. Its end-to-end test (server/e2e_publish_test.goin deckle-hosted) POSTs{"lang":"en"}over the harness socket and expects a 200 with acommit,pushed: trueandfeedback: "polling". Nothing outside deckle calls/api/page/publish.GET /api/badgesgives every pagepublished,modifiedordraft(shown as "unpublished"), compared withmain. A page ismodifiedwhen its bundle or a library file it references differs. Badges show in the page tree, in the page's toolbar and in thestatuscolumn of module lists.main(a never-published page is removed) and is hidden while the page is published. Disable (page actions) sets front-matterdraft: true, and Hugo leaves the page out of the live build. Delete… already warns when other pages link to the page (GET /api/page/refs); Disable does not.scaffold/site/AGENTS.md("Library media publishes with the page").Desired behavior
One Publish
content/andassets/media/, exactly as Publish all does today: pre-flight, empty result, chip, error strip with Retry, build-failed dialog. The same holds inside a host's bar.POST /api/page/publishis gone: it answers 404, like every unknown/api/path.The link check
draft), which would 404 on the live site. The carried pages are every page file undercontent/that is added or modified relative tomain. A carried page that is itself disabled is not checked, because its links never reach the live site.<a href>and link-typed element params, matched by content path and default pretty URL.The
/api/publish-allcontractcheckDraftLinks. A request without it, such as deckle-hosted's{"lang":"en"}, publishes exactly as today and never answers with a warning.{"warning":{"draftLinks":[…]}}shape belonged to the removed endpoint; only the editor reads the new one.Docs
scaffold/site/AGENTS.md's "Library media publishes with the page" describes the one Publish: it carries pending pages and library files together, and refuses when a page it carries would reference a missing library file. The advice for hand commits stays.Decisions
/api/page/publishis removed, not kept without a button. Nothing calls it besides the removed button (deckle-hosted does not), and a publish path nobody uses would still have to be maintained and tested. No deckle sites exist yet (as of 2026-10-06), so there is nothing to stay compatible with./api/publish-allkeeps its name, and for requests that don't ask for the check, its behavior and answers. deckle-hosted's end-to-end test calls it with only{lang}, and changes on the deckle side keep deckle-hosted working unchanged. The button's label changes; the endpoint's name does not.Key interfaces
handlePublishAllanddraftLinkTargets(internal/server/publish.go): the check moves from the per-page handler to publish-all and runs over the pending page files (gitrepo.Repo.ChangedPublishFiles).handlePagePublishgoes, with its route (internal/server/server.go) and its mutation-lock entry (internal/server/mutation.go).publishPathsFor(internal/server/publishset.go) loses its only caller.gitrepo.Repo.PublishPathsandStatusForPathslose their only server caller. They are the package's tested API, so whether the package keeps them is the implementer's call.publishAll,publishPageandPublishOutcome(web/src/api/publish.ts); the header's publish inweb/src/App.tsx;PublishButton,PageEditorNoticesandPageEditorDialogs(web/src/components/PageEditorChrome.tsx); the publish state inweb/src/stores/pageEditor.ts; the feedback store's keys (web/src/publish.ts,PUBLISH_ALL_KEY).handleBadges,internal/server/git.go) don't change.Acceptance criteria
content/andassets/media/.POST /api/page/publishanswers 404.POST /api/publish-allwith only{lang}publishes even when a pending page links to a disabled page, and answers 200 withcommit,pushedandfeedbackas today.scaffold/site/AGENTS.mddescribe one Publish as above, including that it publishes every editor's pending changes. Neither names Publish all or a per-page Publish./api/publish-all.How to verify
make test, which buildsweb/, runs the web tests and runsgo test ./....internal/serverfor the publish-all contract: a{lang}-only request with a link to a disabled page publishes; a request asking for the check warns as above and commits nothing;/api/page/publishanswers 404.Assumptions to check
/api/page/publish, and that deckle-hosted calls/api/publish-allas described above. Both were checked against the deckle-hosted snapshot atc94bc74; check again if it has moved.Out of scope
/api/publish-all, or changing its answers for requests that don't ask for the check.ref/relref, custom permalinks).Blocked by
None - can start immediately