feat(trips): owner publish/unpublish toggle on /trips listing
Add an owner-only publish switch to each /trips card. It POSTs to a new
entry-actions route that mutates trip.md `published` and invalidates the
page-tree cache so the listing, nav and home reflect the change on the
next load. Owner sees drafts (Draft badge); anon/non-owner unchanged.
- U1 EntryScopeGuard::resolveTripChild — resolve a slug to a direct child
of /trips (drafts included, for republish)
- U2 POST /api/v1/trip/{slug}/publish (setTripPublished) — owner-gated
write, strict is_bool body, header-mutation save, audit log
- U3 trip-publish-toggle partial + CSS (role=switch, Draft badge, visible
failure toast, ≥44px target)
- U4 owner-aware /trips listing + card restructure (toggle overlays cover
as a non-anchor sibling; works for coverless drafts)
- U5 home active-trip branch falls back when the active trip is unpublished
- U6 trip-publish.js (confirm/pending/optimistic/revert) + esbuild wiring
Cache note: an in-place frontmatter edit keeps the folder-check cache id,
and driver:auto uses APCu in web memory, so deleteAll()+invalidateCache()
is insufficient — the endpoint also calls apcu_clear_cache().
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
This commit is contained in:
@@ -127,4 +127,36 @@ class EntryScopeGuard
|
||||
}
|
||||
return $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a slug to the trip page that is a DIRECT child of /trips, or null
|
||||
* when the segment is unsafe, the page does not exist, or its parent is not
|
||||
* /trips. The trip-scoped analogue of resolveActiveDailyChild, used by the
|
||||
* publish/unpublish route (KTD4).
|
||||
*
|
||||
* Unlike the front-end listing collections, this does NOT filter on published
|
||||
* state: find() must return drafts so the owner can republish an unpublished
|
||||
* trip from the listing (R7).
|
||||
*/
|
||||
public static function resolveTripChild(Grav $grav, string $slug): ?PageInterface
|
||||
{
|
||||
if (!self::isSafeSegment($slug)) {
|
||||
return null;
|
||||
}
|
||||
$pages = $grav['pages'];
|
||||
// In the API request context the page tree is lazily disabled; enable it
|
||||
// so find() can resolve (mirrors resolveActiveDailyChild). Idempotent.
|
||||
if (method_exists($pages, 'enablePages')) {
|
||||
$pages->enablePages();
|
||||
}
|
||||
$page = $pages->find('/trips/' . $slug);
|
||||
if ($page === null) {
|
||||
return null;
|
||||
}
|
||||
$parent = $page->parent();
|
||||
if ($parent === null || $parent->route() !== '/trips') {
|
||||
return null;
|
||||
}
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user