Fork me on GitHub
#fulcro
<
2021-04-09
>
bbss09:04:11

I've been testing out the fulcro 3.5 raw react stuff, and thanks to hooks (not fulcro raw per se) my components do end up having a lot of lifecycle (react/useEffect ..) stuff that I'd like to abstract away properly some time (probably with more uism). But integrating fulcro with react hooks is really nice to me. I've done an autocomplete recently that uses a union query on the matches. And material-ui useAutocomplete does a bunch of the logic. It's better because earlier I was using :use-hooks? and that wouldn't work as nicely when re-rendering a new hook as I'd need a page refresh.

tony.kay18:04:16

Thanks for the feedback. The autocomplete kinds of cases are definitely the ones where I see the clearest improvements. Other cases might make as much mess as they clean up, but this use-case seems pretty much just a win.

Mark Thomas09:04:21

I’m enjoying playing around with Fulcro RAD. I’ve been able to get something up and running with forms and reports really quickly (and as a relative Clojure newbie!) Out of paranoia, I’m interested in enforcing attribute and form validations in the save-form mutator to guard against malicious network requests. Am I thinking about this the right way or would another step in the save middleware (used by form/pathom-plugin) be a better way to do this?

tony.kay18:04:50

of course you should do that. Save middleware is where you put that logic. RAD cannot write that for you because it does not know anything about your security concerns (how you model permissions/ownership) nor do I personally plan to write a general system for everyone. If you model an ownership system where each entity can be easily checked (e.g. a field on every entity that points to the owner), then a simple permission check in the save middleware is basically this: For each ident in the form diff (each entity to save): Pull the ownership field and check against session. If any fail, deny the save.

thosmos17:04:25

I have a basic RAD report with a :bigdec and a couple of :ref attributes. Is there a way to pull a display field for the refs and format the bigdec without making a custom row component? Here’s what a row looks like at the moment:

{:db/id "17592186557961"}	[TaggedValue: f, 3]	string_value	{:db/id "17592186557686"}

tony.kay18:04:51

make a virtual attribute that represents the label (and can resolve it with input of the row id -> ::pc/resolve on the back-end). Then just add that virtual attribute as a column on the table.

tvaughan18:04:32

I've recently started to see an error. Fulcro and other dependencies have been updated recently (last updated more than a month ago). I can't think of any relevant changes to the source code that may have caused it. Certainly the component in the error message hasn't changed. The error is: > ERROR [com.fulcrologic.fulcro.components:874] - Props passed to http://ns.path.to/ComponentName are of the type function Any hints where I should start to look? This happens when I click on a link that triggers a route change. Thanks

tony.kay18:04:55

We updated Fulcro to try to improve the error messages it gives. Does that one give you a stack trace? If not, you can set a source breakpoint on the components:874 in js tools in Chrome.

tony.kay18:04:17

It is possible that the error is mis-detecting something that is OK, and could therefore be a bug in the new error checking. (The errors should not affect behavior…if it was working, it should still work. they are informational)

tony.kay18:04:56

I’d love to know which it is: problem with your code, or problem with the error check.

Jakub Holý (HolyJak)19:04:34

I likely says "of the type function" because to JavaScript, all cljs data structures look like a function. This is the code:

(when-not ((fnil map? {}) (gobj/get props "fulcro$value"))
                    (log/error "Props passed to" (component-name class) "are of the type"
                      (type (gobj/get props "fulcro$value"))
                      "instead of a map. Perhaps you meant to `map` the component over the props?"))
In this case we shall likely print its .constructor.name, if any.

tvaughan19:04:04

Yes, there is a stacktrace. I've copied it to https://gist.github.com/carrete/f5f2bff186118f408825cfa16f6b8123 It's triggered by the onClick event below:

(defonce ^:private history
  (pushy/pushy
    (fn [path]
      (dr/change-route! app path))
    identity))

(defn route-to!
  [path]
  (pushy/set-token! history path))

:onClick #(route-to! (dr/path-to DrawingUpload))
I've copied and edited the functions above slightly for readabilty. It the path seems wrong, e.g. "/foo/bar" vs. ["foo" "bar"], then I screwed up in my edits

tvaughan19:04:51

Add to which I'm not calling the factory of the component. I'm not sure where that happens when something is routed to

Jakub Holý (HolyJak)19:04:40

In the body of the problematic component, can you log the props to see what type it has?

Jakub Holý (HolyJak)19:04:46

The "function" has a root and a tail and a count so it looks like a list / vector?

tvaughan20:04:14

The props is the component's ident, [:componet/id :drawings-upload]. The component is a singleton, but this seems wrong, right?

3
tvaughan20:04:32

Here's the top part of the component:

(defsc DrawingUpload
  [this {:keys [drawing/kind
                ui/attachment]
         :as props}]
  {:query [:drawing/kind
           :ui/attachment
           form-state/form-config-join]
   :ident (fn [] [:component/id :drawings-upload])
   :initial-state (fn [_]
                    (form-state/add-form-config DrawingUpload
                                                {:drawing/kind nil
                                                 :ui/attachment nil}))
   :route-segment ["drawings" "upload"]
   :form-fields #{:drawing/kind :ui/attachment}}
  (println props)
  ...)

tvaughan20:04:37

I also see WARN [com.fulcrologic.fulcro.routing.dynamic-routing:263] - More than one route target matches ("drawings" "upload") which seems impossible. There are only a few components with route segments. All of them unique

tvaughan20:04:58

As well as ERROR [com.fulcrologic.fulcro.algorithms.form-state:554] - FORM NOT NORMALIZED: [:component/id :drawings-upload] I'm not sure if these are related. The two errors above about props not being a map and duplicate route targets happen when the onClick event is triggered. This error is triggered when form values are changed and set-value! is called

tvaughan20:04:30

Oh this is bonkers. TGIF! I formatted some things which triggered a rebuild and now props is correct. The duplicate routes and not normalized form errors remain though :face_with_symbols_on_mouth:

tvaughan20:04:51

Hold on. It's back after a shift+reload in the browser

tvaughan21:04:22

I don't see the component's ident in :com.fulcrologic.fulcro.algorithms.form-state/forms-by-ident

tvaughan21:04:29

Nor do I see the component in the denormalized db. However, I do see other singleton's under :component/id

tony.kay21:04:07

Remember that initial state is a composition to root for the first animation frame drawn on your entire app. If D.U. isn’t composed to root initial state, then you won’t get that form config, and the props for it will start out nil. If you’ve then done other operations to make the thing sorta work, then it is likely you forgot to actually add the form config (because you thought you already had).

tony.kay21:04:09

Worry less about the details of the warning, and try following the data graph in the DB (e.g. via DB Explorer, where you can click on idents to follow the data tree). If you cannot follow the path from root UI through db to the leaf, then your state is just wrong, and initial state is probably the error.

tvaughan22:04:32

Thanks @U0CKQ19AQ. I understand completely. I do understand it's an indication of a serious problem that I can't navigate to the component in the db explorer in the inspector. I am however at a loss to know where to look next. The onClick event and component, minus its dom output, are above and they seem correct to me. Previously form config state was added in the pre-merge hook, but I don't see that being used in the documentation or templates any more. I saw an example of that being added in the initial-state hook so that's where it is now. It's quite possible that I need to make another similar change. There is no factory for this component. It's listed in the site's router and is rendered when it's routed to via the onClick event. This is where my understanding of fulcro goes into hand wavy magical black box territory. Currently my only guides are the error messages above. When I look at how the initial state is setup, my understanding of fulcro isn't deep enough such that the error is obvious. If things look like what's in the documentation or a template then it looks correct to me, even if it isn't. I'll keep digging though. I'll try to create a smaller, reproduction of the problem. That's helped me before when I was in a similar situation. Thanks again

tony.kay22:04:52

welcome. The magical black box feeling is something you should address first. Get a clear understanding of how Fulcro works…to do any less is to waste a ton of your time. I’d recommend the new grokking Fulcro series if you have already been using it for a while….particularly the state stuff around episode 3a: https://www.youtube.com/watch?v=r1bMQxTr2QA&amp;list=PLVi9lDx-4C_TBRiHfjnjXaK2J3BIUDPnf&amp;index=3&amp;ab_channel=TonyKay

tony.kay22:04:43

Fulcro is very very simple, but if you make assumptions about how it works and just try to follow examples without understanding the specifics it will be much much harder than other things you’ve used. If you take the opposite approach you’ll benefit a lot more, and I hope you’ll find the understanding it (in a deep way) is very much easier than other systems.

tvaughan23:04:34

Thanks. I haven’t seen the new video series, yet. I have watched the original series on youtube, read the book, looked through the templates, and lurked on this channel. I’ll review these things as well as watch the new video series. I had forgotten about it. Thanks for the reminder

tony.kay02:04:59

Yeah, I continue to try to find ways to get across the core bits. There’s a forest vs. tree thing going on that is much worse than I expected.

Tyler Nisonoff22:04:41

is there a way to use load params / query-params with m/returning? Im trying to keep pagination consistent by ensuring load params always include the pagination parameters, but having trouble getting this working with a mutation using m/returning

Jakub Holý (HolyJak)17:04:07

I don't really follow. m/returning is about what the mutation returns while params are about the (extra) inputs it gets?

tony.kay19:04:06

m/with-params

tony.kay19:04:25

but that changes the params of the mutation…

tony.kay19:04:13

that’s an interesting use-case. It’s just AST manipulation…so you could rewrite the returning bit to include params

Tyler Nisonoff19:04:08

I was trying that, but my env -> query-params were still showing up as empty... I also tried pulling it from env -> ast -> params but no luck... will try again later today (on phone at the moment)

Tyler Nisonoff19:04:42

(I tried m/with-params) to be specific Was thinking about a custom ast manipulation, can look into that

tony.kay19:04:14

so, on the server-side the query params in the env are extracted by a plugin I think, right? Not normal pathom logic.

tony.kay19:04:34

so, you might have to tweak both sides, since the returning logic is a post-parse from the mutation processing

tony.kay19:04:50

but as far as adding params to the query itself, I think that should work…give me a sec

tony.kay19:04:18

Try SHA 2b5dff2e9f34ff6f47a5f1bcc36bc088a14c552d

tony.kay19:04:43

I added a returning that supports an extra arg for query params, which it will then put on the returning query. You’ll still need to look for them (they’ll be on the first prop of the query AST on the server)…to get them into the env would require a bit more work I think

Tyler Nisonoff01:04:47

Thanks Tony, will try it out when home!

Tyler Nisonoff16:04:35

@U0CKQ19AQ having trouble testing it.. getting:

Syntax error compiling at (com/fulcrologic/fulcro_i18n/i18n.cljc:102:22).
No such var: comp/*shared*
Im using:
com.fulcrologic/fulcro-i18n            {:mvn/version "0.0.5-alpha"}
` And fulcro-rad depends on i18n via
com.fulcrologic.rad.picker-options
it looks like comp/*shared* may have been removed in commit: 292025c1d

Tyler Nisonoff16:04:37

i think i may just have to update i18n to use rc/*shared* — can try that EDIT: compiling now — testing

tony.kay17:04:42

bah…I moved that var

tony.kay17:04:51

that’s a pain

Tyler Nisonoff17:04:25

no worries, got it working! Heres the query-params logic:

(def query-params-to-env-plugin
  "Adds top-level load params to env, so nested parsing layers can see them."
  {::p/wrap-parser
   (fn [parser]
     (fn [env tx]
       (let [children     (-> tx eql/query->ast :children)
             query-params (reduce
                            (fn [qps {:keys [type params] :as x}]
                              (cond-> qps
                                (and (not= :call type) (seq params)) (merge params)))
                            {}
                            children)
             env          (assoc env :query-params query-params)]
         (parser env tx))))})
I added a conditional to check if the child query is of type call, then recursively check the params on its query, and add that to the env. Not sure if thats the best general-purpose logic, as ideally they’d only show up in the env after the mutation but during the load, but I’ll have to look deeper into pathom’s plugin system to see if thats doable — this works for me at least for now — and if we like it in general i can add a PR

tony.kay17:04:56

Try this commit for the shared fix: 50f7c0d6dce72d7f55634db84b9acabda1ed5df5

tony.kay17:04:38

be interested in knowing that that fixes your compile error. I do not intend for 3.5 to break projects

Tyler Nisonoff17:04:29

@U0CKQ19AQ that fixed it, thanks!

Tyler Nisonoff17:04:12

after releasing 3.5 i can submit a PR for i18n to update to rc/*shared* if thats still the strategy

tony.kay17:04:34

no, I moved it back

tony.kay17:04:40

there was no need to move it after all, which is good

Tyler Nisonoff17:04:30

if you have thoughts on if adding the query-params from the mutations load to the env in query-params-to-env-plugin is something you’d like merged in, happy to make a PR or work on a better approach — definitely understand if you dont have time to think about it though.

tony.kay17:04:57

It would be nice to have it. The load primitive of Fulcro always has a single top-level key, so for single loads that plugin is fine (at the parser level), but mutations (as you noted) are not so clear-cut, since more than one can be sent, and as a result each could have its own query params. So, the general solution would have to change the env value based on which mutation was running…but env is immutable, so some possible solutions are: • Merge all of the query params together into one map. Key collision is then possible and undesirable. • Figure out how to rewrite the env after a mutation. I don’t know if @U066U8JQJ has any fancy tricks built-in, but you could use wrap-parser to put an atom in the top-level env like :alternate-env (atom nil) and then add a wrap-read and wrap-mutate that pass that as env when it is non-nil. That way a return on a mutation that needs to change query params could do so by resetting the alt env. • Others???

👍 3