host: typed relations — Phase 3, tags as posts
A tag is just a post that is-a tag; tagging is a "tagged" edge to it. End to end: mark a post a tag, tag posts with it, see a post's tags and a tag's members. - helpers: host/blog-is-tag? (= is-a? slug "tag"), host/blog-tags (out tagged), host/blog-tagged-with (in tagged), host/blog-instances-of (a type's members, O(#subtypes) not O(#posts) — the efficient candidate source). - picker generalised to be KIND-AWARE and MULTI-INSTANCE: relate-options takes &kind=, candidates come from the kind's registry :candidates (all/tags/types); /relate-picker.js wires every .relate-picker box by data-kind (a Related picker and a Tags picker now coexist on the edit page). - render: post page gains a "Tags" block; a tag post additionally lists "Tagged with this" (its members). edit page: a Related editor + a Tags editor + an "is this post a tag" toggle (reuses /relate kind=is-a — no new route). - GOTCHA (again): host/blog--relation-editor read host/blog-out INSIDE its quasiquote -> VmSuspended/500 under http-listen + durable edges; moved the read to a let before the quasiquote (conformance can't see it — in-memory store; the ephemeral Playwright run caught it). 6 conformance tests (is-tag?, instances-of, tag+tagged-with, tagged picker offers only tags, related picker still all, is-a-tag toggle) -> 261/261. Playwright multi-picker 4/4. Verified live: ocaml made a tag, welcome tagged ocaml, Tags block + Tagged-with-this both render. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -369,6 +369,32 @@
|
||||
(host-bl-test "type-valid? is vacuously true with no schemas (gradual)"
|
||||
(host/blog-type-valid? "ppost" "(p \"anything\")") true)
|
||||
|
||||
;; -- Phase 3: tags as posts -- (ocaml is-a tag, from the seed-types test above)
|
||||
(host-bl-test "is-tag?: a post that is-a tag is a tag; others are not"
|
||||
(list (host/blog-is-tag? "ocaml") (host/blog-is-tag? "ppost"))
|
||||
(list true false))
|
||||
(host-bl-test "instances-of tag includes the tag posts"
|
||||
(contains? (host/blog-instances-of "tag") "ocaml") true)
|
||||
(host-bl-test "tag a post: it appears in tags + tagged-with (inverse)"
|
||||
(begin
|
||||
(host/blog-relate! "ppost" "ocaml" "tagged") ;; ppost tagged ocaml
|
||||
(list (contains? (host/blog-tags "ppost") "ocaml")
|
||||
(contains? (host/blog-tagged-with "ocaml") "ppost")))
|
||||
(list true true))
|
||||
(host-bl-test "tagged picker offers only tags (kind=tagged)"
|
||||
(let ((body (dream-resp-body (host-bl-app (host-bl-req "/particle/relate-options?kind=tagged")))))
|
||||
(list (contains? body ">OCaml<") (contains? body ">P Article<")))
|
||||
(list true false))
|
||||
(host-bl-test "related picker still offers all posts (kind defaults to related)"
|
||||
(contains? (dream-resp-body (host-bl-app (host-bl-req "/particle/relate-options"))) ">P Doc<")
|
||||
true)
|
||||
(host-bl-test "is-a-tag toggle marks a post a tag via /relate kind=is-a"
|
||||
(begin
|
||||
(host-bl-wapp (host-bl-send "POST" "/pdoc/relate" "Bearer good"
|
||||
"application/x-www-form-urlencoded" "other=tag&kind=is-a"))
|
||||
(host/blog-is-tag? "pdoc"))
|
||||
true)
|
||||
|
||||
;; -- experimental unguarded create-only route (POST /new, no auth) --
|
||||
(define host-bl-oapp (host/make-app (list host/blog-open-create-routes host/blog-routes)))
|
||||
(host/blog-use-store! (persist/open))
|
||||
|
||||
Reference in New Issue
Block a user