fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
mruzekw 2020-09-13T00:11:17.424400Z

Hi all, what is the idiomatic way in Fulcro to create a “private” route? I see :allow-route-change? but I don’t see any access to the app-db there. I’d basically be looking to see if we have a token or not, and if we don’t redirect to a login page.

mruzekw 2020-09-13T00:16:51.425400Z

Also, given those semantics I wonder how a route can be protected at any point of entry. As :allow-route-change? implies change from the current route to another.

mruzekw 2020-09-13T00:21:04.426200Z

Or would :will-enter + route-deferred be enough?

(defsc Protected [this props]
  {:ident         (fn [] [:component/id ::protected])
   :query         [:protected]
   :initial-state {:protected nil}
   :route-segment ["protected"]
   :will-enter (fn [app route-params]
                 (if (not (has-token? app))
                   (dr/route-deferred [:component/id ::protected] #((dr/change-route app ["main"])))))}
  "Protected")

tony.kay 2020-09-13T00:37:21.428500Z

Fulcro 3.2.17 on Clojars. This release includes a more completely tested sync transaction processing plugin. Still considered slightly experimental, so please use heavily in dev before considering in production. @bbss Book has been updated. I changed how you install it, since it needs to modify a number of things in the app definition now. See http://book.fulcrologic.com/#_synchronous_operation I’ve tested it against the Fulcro RAD demo, which is rather heavy hitting on full-stack features with nested transaction submission and it seems fine.

tony.kay 2020-09-13T00:40:45.431500Z

@mruzekw you could take a look at how I coded that sort of thing in the RAD demo. Initialization is really a separate step from general operation, and I think it should be treated as such. Trying to make one thing do many things is generally a path to confusion. Your network layer will protect the data, so really what you’re asking is “can I wait to do the routing until I’ve figured out auth?“…which of course requires you to know what you’re doing with auth, how you’re handing HTML5 routing, etc etc. There is no “one way”, nor can I code a pre-built solution into the general library…thus why it is in a demo, where I have the auth and HTML5 routing pinned down.

tony.kay 2020-09-13T00:41:37.432400Z

You could (and should) pre-route to some kind of initial page like loading or landing, then once your session check has returned eval the URL and attempt to updat ethe route, but that also involves capturing the URL before your routing system changes it.

tony.kay 2020-09-13T00:42:09.432700Z

Again, see RAD demo

tony.kay 2020-09-13T00:42:32.433100Z

@limix Same comment: See RAD

Jakub Holý 2020-09-13T13:15:41.447900Z

BTW I believe the Authorization isn't really flashed out yet.

tony.kay 2020-09-13T18:29:21.455100Z

it is not fully. I would not even consider that alpha…it’s a whole complete thing of its own that I don’t have time to deal with

tony.kay 2020-09-13T18:29:32.455300Z

it’s more in the demo just as an example

mruzekw 2020-09-13T00:42:54.433800Z

Okay, thanks for explaining. Will give that a look

tony.kay 2020-09-13T00:42:54.433900Z

also the book

mruzekw 2020-09-13T00:43:32.434200Z

“can I wait to do the routing until I’ve figured out auth?” Yes, this is exactly my question :thumbsup:

mruzekw 2020-09-13T00:43:37.434500Z

Thanks again

az 2020-09-13T01:56:43.435700Z

Thank you @tony.kay

az 2020-09-13T01:58:05.435900Z

@ajsnow2012 - I meant for access to certain pieces of data after they have authenticated.

zhuxun2 2020-09-13T06:03:53.442500Z

For a state component whose query I never use for loading (and only for read-only querying,) is it okay for me to inline the whole link query? For example is it okay to do:

(defsc Badge [this props]
  {:ident (fn [] [:component/id :badge])
   :query [{[:component/id :current-session] [{:session/account [:account/id :account/name :account/avatar]}]}]}
  (div ...))
As opposed to creating a one-off component to replace the [:account/id :account/name :account/avatar] with (comp/get-query ...)?

tony.kay 2020-09-13T18:40:22.455500Z

If accounts are normalized, then I would not do that: you’ll end up with a non-normalized account stuck in there, and then when you do a form to let them change their name/avatar, you’ll have to screw with the non-normalized stuff.

tony.kay 2020-09-13T18:40:46.455700Z

but does it “work”? Yeah, it’ll “work” for some value of “reasonably well”

tony.kay 2020-09-13T18:41:36.455900Z

Nested link queries should trigger normalization…you could write an AccoutQuery component with query/ident just for that nested part.

zhuxun2 2020-09-14T05:26:50.457800Z

@tony.kay Hmmm... in that case do I create n versions of AccountQuery, for the n different views an Account is represented as? Otherwise, if I only create just one all-encompassing AccountQuery that has all the 20 things an account has, then wouldn't I be asking too much in a simple Badge?

zhuxun2 2020-09-14T05:30:25.458200Z

@tony.kay and also, when would I get non-normalized account if would never do (load! ... Badge)? The query of Badge will only be used for pulling data from the client db, isn't it?

tony.kay 2020-09-14T15:59:14.460500Z

Yes, you write different components with different queries, but using the same Ident. That’s most of the point, remember? Being able to ask for what you need, when you need it?

zhuxun2 2020-09-13T06:06:15.444200Z

Seems like (comp/get-query ...) is not necessary in link queries as link queries are not used in the normalization process

2020-09-13T13:29:17.449Z

one difference I have with the synchronous transactions is this error/warning pops up:

timbre_support.cljs:80 ERROR [com.fulcrologic.fulcro.components:858] -  A Fulcro component was rendered outside of a parent context. This probably means you are using a library that has you pass rendering code to it as a lambda. Use `with-parent-context` to fix this.
I guess that stems from a map-indexed in that component, adding with-parent-context there seems to fix it 🙂

Helins 2020-09-13T13:40:11.451200Z

I get odd behavior in Inspect. When I boot the app, I can see the DB and everything. After +/- 10 seconds, everything disappear and I see only an empty map, nothing in DB explorer either. Nothing changes, nothing reloads, no transactions... what on earth could be the reason?!

zhuxun2 2020-09-13T17:23:45.452800Z

@adam678 I sometimes see exactly the same thing as well. It usually happens when there's a lot of transations going on. Be curious to know what exactly causes it.

Helins 2020-09-13T17:27:27.454Z

@zhuxun2 Here is the thing, there are basically a couple of simple transactions at boot, really not much going on. Usually it performs fine under heavy workload

tony.kay 2020-09-13T18:26:24.454500Z

@bbss hm, that’s interesting. What is the actual rendering code causing that?

2020-09-14T08:13:30.458400Z

(defsc UiPhraseLocation [this {:phrase-location/keys [from to id] :as props
                               :ui/keys              [extraction-phrase]}]
  {:use-hooks? true}
  (let [[open? set-open]   (react/useState)
        {:keys [source i]} (comp/get-computed props)
        phrase             (subs source from to)
        loading?           (get-in props [df/marker-table [:fetching id]])]
    ($ ListItem
       {:style #js {:display        "grid"
                    :gridTemplate   "'top-bar' 50px
                                     'ana'     auto / 1fr"
                    :padding        "0px"
                    :background     (if (odd? i)
                                      "rgba(220, 240, 220, 0.31)"
                                      "rgba(200, 230, 200, 0.31)")}
        :key (str id)}
       ($ ButtonBase
          {:onClick #(do (set-open (not open?))
                         (when-not (or extraction-phrase loading?)
                           (df/load! this [:phrase/phrase phrase]
                                     ExtractionPhrase {:target [:phrase-location/id id :ui/extraction-phrase]
                                                       :marker [:fetching id]
                                                       :parallel? true})))
           :style #js {:gridArea      "top-bar"
                       :height        "50px"
                       :justifyContent "space-between"
                       :background (if (odd? i)
                                     "rgba(220, 240, 220, 0.31)"
                                     "rgba(200, 230, 200, 0.31)")}}
          ($ Typography {:variant "h5" :color "secondary"
                         :style #js {:textOverflow "ellipsis"
                                     :overflow     "hidden"
                                     :whiteSpace   "nowrap"
                                     :width        "80%"
                                     :position     "absolute"
                                     :left "15px"}} phrase)
          ($ :div {:style {:position "absolute" :right "15px" :top "15px"}}
               (if open? ($ ExpandLess) ($ ExpandMore))))
       ($ Collapse
          {:style #js {:gridArea "ana"}
           :in open? :unmountOnExit true :timeout "auto"}

          (if loading?
            ($ LinearProgress {})
            (ui-extraction-phrase extraction-phrase))
          #_(for [[i [form short long]] (map-indexed vector forms)]
              ($ Typography {:variant "h6"  :color "secondary" :key (str i " - " form " - " i)
                             :style #js {:alignSelf "center"}}
                 (str form " - " short " - " long )))))))

(form/defsc-form PhraseLocation [this {:phrase-location/keys [from to id] :as props}]
  {::form/attributes [extr/phrase-loc-from
                      extr/phrase-loc-to
                      extr/phrase-loc-id]
   ::form/query-inclusion [{:ui/extraction-phrase (comp/get-query ExtractionPhrase)}
                           [df/marker-table '_]]
   ::form/id          extr/phrase-loc-id
   :use-hooks?        true})

(def ui-phrase-location (comp/factory UiPhraseLocation {:keyfn :phrase-location/id}))

(form/defsc-form Extraction [this {:extraction/keys [phrase-locations source]}]
  {::form/id         extr/id
   ::form/attributes [extr/source extr/phrase-locations extr/id]
   ::form/subforms   {:extraction/phrase-locations
                      {::form/ui PhraseLocation}}
   :use-hooks? true}
  (map-indexed (fn [i phrase-location]
                 (comp/with-parent-context this
                   (ui-phrase-location (comp/computed phrase-location {:i i :source source}))))
               phrase-locations))

2020-09-14T08:15:39.458600Z

use-hooks? seems not to work on defsc-form so I made a different component for that. The issue seemed to stem from the map-indexed I thought maybe the Collapse was suspect, but the render of UiPhraseLocation didn't seem to matter.

2020-09-14T08:20:04.458800Z

not sure if it matters but the Extraction gets rendered with a comp/factory -> ui-extraction like so:

(when (:material/extraction selected-material) 
  (ui-extraction (:material/extraction selected-material)))

tony.kay 2020-09-14T15:58:00.460200Z

map-indexed is lazy, and since it is at the top of the body it isn’t getting forced. I bet if you put it in a div it’ll be fine. The DOM elements all forcechildren, but defsc does not. That’s technically an oversight on my part, but I guess no one has tried it quite that way

2020-09-15T05:46:54.003700Z

alright, makes sense! cheers.

tony.kay 2020-09-13T18:45:23.456100Z

So, this can happen for a number of reasons (some still unknown). One I’ve seen is if local state in the Inspect tool ends up with non-serializable data (e.g. you put a lambda or component into app state db). You can try to fix that by right clicking on Inspect and Inspecting the Chrome plugin itself, then go to application section and clear local data (local storage etc). You can also reinstall the plugin to clear that. If it is working for a little bit and then dying, could be the same sort of thing..something in an early tx hits a bug I have not yet found. Again, Inspecting Inspect in Chrome’s devtools and looking at that console (not your primary one) might yield more insight: . Right-click within Fulcro Inspect’s tab area and choose “Inspect”, that will pop open a new window with Chrome devtools running against Fulcro Inspect. . Look at the console tab, and Application tab’s local storage

👍 1
tony.kay 2020-09-13T18:47:57.456400Z

I tried it on a MUCH larger app, and it is fine. I’m guessing you had a pre-existing issue there that was not reporting for some reason. Be interested in seeing that code. I am seeing the routing system reporting more issues because of the change in overall operational semantics, esp if you change route to a non-leaf in RAD…will need to track that down, but at the moment it seems harmless.