Fork me on GitHub

you'd have to show your call to ui-art-editor where you pass the props. Parent is always responsible for putting the props in the component. Fulcro satisfies the root query


so, my guess is you didn't make a join in the parent


it's a router target so the parent is just the TopRouter:

(dr/defrouter TopRouter [this props]
  {:router-targets [Main Gallery ArtEditor Signup SignupSuccess Settings]})
I didn't wrap it in a factory. is there anything else I'm missing?


nevermind, I resolved it-- think it was a combination of needing (str uuid) and also a refresh issue. thanks for your help!

Pragyan Tripathi08:08:17

I am using fulcro rad to build admin application. I needed to modify rendering of each row in a report, Along with some row controls.

(def block-key :com.vadelabs.turbo-blocks.block/Component)

(defsc RowItem
  [this props]
  {:ident :block/id
   :query (fn [_]
            (turbo.core/block-query block-key))
   :initial-state (fn [_] {})}
  (let [ui-block (turbo.core/block-factory block-key)
        properties (map (fn [item] (:property/name item)) (:block/properties props))]
     (turbo.dom/td {} (str (:block/identifier props)))
     (turbo.dom/td {} (str (:block/context props)))
     (turbo.dom/td {} (str (:block/type props)))
     (turbo.dom/td {} (pr-str properties))
     (turbo.dom/td {} (ui-block props)))))

(defsc-report Feed [this props]
  {ro/route "blocks"
   ro/source-attribute :block/feed
   ro/row-pk block/id
   ro/run-on-mount? true
   ro/columns  [block/identifier block/context
                block/type block/properties block/preview]
   ro/BodyItem RowItem
   ro/row-actions         [{:label  "Edit"
                            :action (fn [this {:block/keys [id]}]
                                      (form/edit! this Form id))}
                           {:label  "Delete"
                            :action (fn [this {:block/keys [id]}]
                                      (form/delete! this :property/id id))}]})
How can I add row-controls buttons in the rendering.


you mean the ones the plugin normally renders? You could look at the source of the plugin and see what it does.


Otherwise, look at the state machine definition source, and see what events are available, and trigger events that do what you want


Your computed props (third arg of component) has a bunch of useful stuff

Pragyan Tripathi18:08:05

I have update the example code. I just wish to row-actions. Wondering if there is an easier way to do it.

Pragyan Tripathi18:08:06

Also is there a way to render nested Form with same structure as a parent:

(defsc-form TForm [this props]
  {fo/id block/id
   fo/title "Blocks"
   fo/attributes [block/identifier block/context block/type
                  block/properties block/children]
   fo/route-prefix "block"
   fo/subforms {:block/properties {fo/ui property/Form}}})

(defsc-form Form [this props]
  {fo/id block/id
   fo/title "Blocks"
   fo/attributes [block/identifier block/context block/type
                  block/properties block/children]
   fo/route-prefix "block"
   fo/subforms {:block/properties {fo/ui property/Form}
                :block/children {fo/ui TForm}}})
I wished :block/children to be infinitely nestable. Is it possible?


Of course it is possible, but it isn't something that RAD supports out of the box.

👍 3

I'm writing some specs in a cljc namespace:

(ns sheluchin.specs
  (:require [clojure.spec.alpha :as s]
            [com.fulcrologic.guardrails.core :refer [>defn >def | ? =>]]))

; (defn is-crux-node? [n] [any? => boolean?]
;   (instance? crux.api.PCruxNode n))

(>def :note/text (s/and
                    (complement clojure.string/blank?)
                    #(<= (count %) 30)))
(>def :note/id any?)  ;; TODO: use a better predicate
(>def ::note (s/keys :req [:note/text :note/id]))
They seem to work from CLJ but not from CLJS:
Execution error (Error) at (<cljs repl>:1).
Unable to resolve spec: :sheluchin.specs/note
Testing using the same invocation in both places:
(s/explain :sheluchin.specs/note {})
What might I be doing wrong here?


I thought maybe it's the use of clojure.string, so I removed all references to that. Didn't help.


Weird.. restarted everything and it seems to work now.


is there a good way to compose queries that might be circular? pretty sure there's a better way to do this:

(defsc TraitTypeAndTraits [this props]
  {:query [:trait-type/uuid {:trait-type/traits [:trait/uuid]}]
   :ident :trait-type/uuid})

(defsc TraitType [this props]
  {:query [:trait-type/uuid :layer-group/filename
           :trait-type/name :layer-group/z-index]
   :ident :trait-type/uuid})

(defsc Trait [this props]
  {:query [:trait/uuid :layer/filename :trait/name
           {:trait/trait-type (comp/get-query TraitType)}]
   :ident :trait/uuid})


your example isn't clear to me...circles in queries are not really possible without declaring alternate classes, since the call to get-query would be infinitely recursive. Is the data actually a circle in the database graph?


Recursive queries get you through most of those, but if the separation of top and bottom is more than one apart, then you've got a challenge.


if you put more exposition with your example and explain what you are trying to actually do (instead of me having to infer it from your code) then it would be easier to help

Jakub HolĂ˝ (HolyJak)18:08:55

Hi! Any idea why a ws/defcard renders an empty card and its Inspect button does nothing? I think I copied all relevant from fulcro-template. The code is here, everything related was added by The key part of the code is

(defsc ColorChangingSquare [this {:ui/keys [red?]}]
   {:query [:ui/red?]
    :ident (fn [] [:component/id :ColorChangingSquare])
    :initial-state {}}
   (dom/div {:style {:background-color (if red? "red" "blue")}}
; ...

(ws/defcard fulcro-demo-card
              {::ct.fulcro/root       ColorChangingSquare
               ::ct.fulcro/wrap-root? true}))

Jakub HolĂ˝ (HolyJak)19:08:40

@tony.kay sorry to bother but do you have any tips for how to troubleshoot this? 🙏


Check the requires and make sure you didn't get F2 stuff 😛


make sure you're using my fork of devcards


your shadow aliases do not include that stuff


so your deps is either wrong, or your shadow-cljs aliases are


but I would expect a compile error...


oh, I see, you're running shadow from deps...that's why your classpath "works"

Jakub HolĂ˝ (HolyJak)20:08:47

It runs and the workspaces shows

Jakub HolĂ˝ (HolyJak)20:08:33

I am running clj -M:serve-puzzles which has dependency on workspaces

Jakub HolĂ˝ (HolyJak)20:08:28

Ah I see what you are saying, I forgot about shadow-cljs.edn and its :deps {:aliases []} Not sure how it plays here. Maybe it does not matter the way I am running it, from deps?




I see it start


Inspect button works


card is blank

Jakub HolĂ˝ (HolyJak)20:08:06

Ok, you are luckier than me if Inspect works for you 🙂 Any idea why the card would be blank?

Jakub HolĂ˝ (HolyJak)20:08:24

ah, inspector works now for me too, after some reloads (and I have also added :serve-puzzles to shadow's aliases)


I added :ui/red? false to initial state


and now it renders


I think perhaps the generated root checks to see that the props contain something to avoid errors


and your props were empty

Jakub HolĂ˝ (HolyJak)20:08:18

Ah, thanks a lot! I did not even think about that possibility. You saved me 🙂


yeah, rendering empty props can cause crashes in components that don't expect it, so I think that was the reasoning on the generated root

👍 3

if you had not used wrap-root? you would not have been confused. Generated code is sometimes "too" helpful 🙂

simple_smile 3
Jakub HolĂ˝ (HolyJak)20:08:59

do you know where is the generated root defined?


just jump into the source of that helper


yeah, line 62


(if (seq root) ...

Jakub HolĂ˝ (HolyJak)20:08:44

what about me sending a PR that adds an else branch displaying some helpful error message?


ok by me

👍 3
❤️ 3

I don't think it needs to say "WARNING"...just something like "Your top-level component cannot be rendered because the props for it are nil or empty. Please make sure you included a non-empty initial state in that component"

👍 3
Jakub HolĂ˝ (HolyJak)18:08:14

A related question: should one prefer com.github.awkay/workspaces {:mvn/version "1.0.2"} or nubank/workspaces "1.1.1" which seem to also support Fulcro 3?


I use mine. nubank is written with F2, and thus pulls F2 onto your classpath, leading to all sorts of potential unfortunate accidents on require

👍 3

I am trying to do lazy loading in a RAD report — @tony.kay had helped me write an “:all-cards” resolver, but the query now forces loading of all card comments, because I added comments as a part of each Trello card. (And there can be thousands of cards in a list, and so it could force thousands of Trello API calls.) Is there a way suppress loading of certain fields in a RAD report, something like :without in df/load!? (I’m thinking through how to do lazy loading of comments for just the cards on the current page with @holyjak)


Remember that first and foremost RAD is about patterns not artifacts. The fact that I've supplied a report artifact is a convenience, and one in which I am not planning to ever cover every possible use-case. Doing so is folly IMO. Instead, everything has an escape hatch. When you get to cases like this you need to take more control of the overrides of core bits of that artifact (which it is designed to allow). Specifically, what you are asking for requires that you override and tune the state machine, and add whatever custom options you need it to support.


Basically, as soon as you go beyond the basic case, you have to take more and more control. Fortunately, the patterns establish ways where you can easily reuse those advancements throughout your app


Often, you can work through some of these cases by being a little inventive within the model itself: Comments need not be resolved by a report at why are you asking it to to begin with?


the report only loads what you tell it to load. Don't include the column in question?

Jakub HolĂ˝ (HolyJak)19:08:48

We want to show the comments but for performance reasons we want to load them async/lazily and only for the currently visible page. It is essentially just a perf. optimization.


yes, and if that is what you want you must customize the state machine to do a more complex thing than it currently knows how to do

👍 3

• Add an option to the report that supports the concept (some field is not loaded by default, update state machine to look for that and use it in :without) • Add an event that does the proper thing, or augment one (modify the "next page" stuff to trigger focused loads for just the rows that are appearing)

Jakub HolĂ˝ (HolyJak)20:08:40

Thank you very much! I thought of a number of workarounds but not about this optimal approach 🙂


Eventually it would be nice to have some "beefed up" state machine definitions in a library ppl could choose from.


but the state machine is just a map, so it's pretty easy to augment one without copying source...just assoc against the existing one

Jakub HolĂ˝ (HolyJak)20:08:49

That sounds simple enough, thank you!