fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
Mr. Savy 2021-01-30T04:03:30.135100Z

when deploying my fulcro app it crashes saying postgres refused to connect. does anyone know if there's more information available anywhere for configuring the prod.edn file in the template? my guess is it may be something in there?

Jakub Holý 2021-01-30T11:41:09.135500Z

No exception? No stack trace? Have you debug Iogging on? (see default.edn)

Mr. Savy 2021-01-30T18:49:59.173500Z

the specific error is Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. there's a number of thing that can be causing this but my understanding is that it's ssl rleated.

Jakub Holý 2021-01-30T19:17:10.185Z

if you suspect that there is some java ssl system property you can set to get detailed logs (not related to Fulcro in any way)

👍 1
Timofey Sitnikov 2021-01-30T12:14:33.139400Z

@holyjak, first of all awesome writeup and I do have a question, looking at the first diagram of https://github.com/fulcro-community/guides/blob/main/minimalist-fulcro-tutorial/index.adoc#an-overview-of-fulcro, makes me wonder where does the application code fit in? So there are resolvers, the front end (the defsc macro), parsers and so on. I wonder if it is possible to make a diagram showing where each of these elements fit in.

Jakub Holý 2021-02-01T09:28:57.196800Z

@timofey.sitnikov I have added a section for your figure, see https://github.com/fulcro-community/guides/blob/main/minimalist-fulcro-tutorial/index.adoc#review

tony.kay 2021-02-01T16:18:47.198Z

Re-reading my own comment….“There’s no alternative way to talk to a remote” means “through Fulcro’s mechanims”…you can of course use http client or any such thing to grab data, and one you have data you could use swap! against Fulcro’s state atom, but you’d get zero support from Fulcro that way. By at least using merge-component! you’d get normalization and refresh. By using the official mutation/remote system you get even more. Just clarifying.

👍 1
Jakub Holý 2021-01-30T12:50:23.147200Z

Thank you! Do you think it is worth it? Defsc clearly belongs to the UI, parser and resolvers to Pathom, defmutation to both. It is simple, no?

2021-01-30T12:54:09.149900Z

I'm having trouble getting fulcro-rad to start up. I'm using a copy of fulcro-rad-demo as is - I have not made any changes yet. When I execute shadow-cljs watch main, I get this: Execution error (IllegalArgumentException) at shadow.build.js-support/eval15243$loading (js_support.clj:1). No matching field found: getRegisteredGroups for class com.google.javascript.jscomp.DiagnosticGroups It looks like a version conflict in the Google closure compiler code being called by shadow-cljs? The nearest issue I have found is https://github.com/thheller/shadow-cljs/issues/488. I followed Thomas' https://shadow-cljs.github.io/docs/UsersGuide.html#failed-to-load, and checked dependencies. My project was using a slightly older version of closure-compiler-unshaded, as listed https://clojars.org/thheller/shadow-cljs/versions/2.8.110 for the corresponding version of shadow-cljs. I forced the correct version of closure-compiler-unshaded in my deps.edn, but it made no difference. I also checked the source code of closure-compiler-unshaded and it does contain the getRegisteredGroups method. I have also confirmed that the correct version of the library is being used with clj -Spath. Has anyone experienced this before? I find it strange that the exact copy of the repo as is, runs into this problem?

thheller 2021-01-30T13:05:42.150900Z

@andre.richards that is definitily a version conflict. should be

org.clojure/clojurescript 1.10.773
com.google.javascript/closure-compiler-unshaded v20200830

Timofey Sitnikov 2021-01-30T13:13:53.151900Z

It becomes simple after a while, but there are a lot of components that fit together and it is not easy to grasp it right away. I tried to put something together quickly, but it needs more work. The idea is to gain understanding of how everything fits together.

2021-01-30T13:15:01.152300Z

Thanks @thheller. I changed it to those versions, but still get the same error...

Timofey Sitnikov 2021-01-30T13:15:10.152400Z

@holyjak, let me know what you think.

thheller 2021-01-30T13:17:33.152900Z

did you restart the shadow-cljs process after? did you change it in the correct place?

2021-01-30T13:20:35.154900Z

Hi, yes I did restart. If I do clj -Spath to print the classpath, I get this (I split and filtered classpath using clojure just to make it easier to find correct info): ("/Users/andre/.m2/repository/org/clojure/google-closure-library/0.0-20191016-6ae1f72f/google-closure-library-0.0-20191016-6ae1f72f.jar" "/Users/andre/.m2/repository/org/clojure/google-closure-library-third-party/0.0-20191016-6ae1f72f/google-closure-library-third-party-0.0-20191016-6ae1f72f.jar" "/Users/andre/.m2/repository/com/google/javascript/closure-compiler-externs/v20200830/closure-compiler-externs-v20200830.jar" "/Users/andre/.m2/repository/com/google/javascript/closure-compiler-unshaded/v20200830/closure-compiler-unshaded-v20200830.jar")

thheller 2021-01-30T13:21:11.155100Z

and which clojurescript version? and which shadow-cljs? they all need to align otherwise you get this error

2021-01-30T13:28:24.157400Z

ClojureScript: ("/Users/andre/.m2/repository/org/clojure/clojurescript/1.10.773/clojurescript-1.10.773.jar") shadow-cljs: ("/Users/andre/.m2/repository/thheller/shadow-cljsjs/0.0.21/shadow-cljsjs-0.0.21.jar" "/Users/andre/.m2/repository/thheller/shadow-cljs/2.8.110/shadow-cljs-2.8.110.jar" "/Users/andre/.m2/repository/thheller/shadow-util/0.7.0/shadow-util-0.7.0.jar" "/Users/andre/.m2/repository/thheller/shadow-client/1.3.2/shadow-client-1.3.2.jar") This is the version of shadow-cljs specified in the fulcro-rad-demo. Should I try the latest shadow-cljs? I have included my config files

thheller 2021-01-30T13:29:06.158200Z

well as I said .. they need to align. and that shadow-cljs version is too old for the above

thheller 2021-01-30T13:30:05.158900Z

yes, you should try 2.11.15. or get the matching versions for the older ones https://clojars.org/thheller/shadow-cljs/versions/2.8.110

Jakub Holý 2021-01-30T13:36:33.160200Z

Cool! Sadly neither Slack nor my phone can display it. Will try later on PC

2021-01-30T13:39:54.162300Z

Thanks, 2.11.15 is working. I promise, I did earlier match my versions of clojurescript and Google closure compiler to https://clojars.org/thheller/shadow-cljs/versions/2.8.110 :man-shrugging: Thanks again for your help. I'll sponsor you a drink on GitHub if you are listed there for sponsorship. 👍

thheller 2021-01-30T13:40:55.163Z

ideally you just have shadow-cljs as a dependency then you don't need to worry about it for the most part

thheller 2021-01-30T13:41:17.163500Z

but that also runs into trouble if other libs declared dependencies on other clojurescript versions that they shouldnt

thheller 2021-01-30T13:41:23.163700Z

so yeah its a bit messy unfortunately

Timofey Sitnikov 2021-01-30T13:46:22.163900Z

@holyjak OK, here you go.

❤️ 3
2021-01-30T13:47:31.165Z

Understood, thanks 🙂 And thanks for a wonderful library! 👏👏

Jakub Holý 2021-01-30T13:51:12.165200Z

Nice! Yes, I guess something like this could be useful. Do you want to polish it when you have time?

Timofey Sitnikov 2021-01-30T13:59:56.165400Z

Where would it fit into the doc? How about adding it into the doc and polishing it as we go?

Timofey Sitnikov 2021-01-30T14:00:10.165600Z

One more version

❤️ 2
Timofey Sitnikov 2021-01-30T14:08:26.166Z

OK, so I created a pull request for you and when you have time, maybe you can place it into the right section and I will keep working on it.

Timofey Sitnikov 2021-01-30T14:09:04.166200Z

I am going to make one more post, on the main thread, maybe I can get some good feedback.

Timofey Sitnikov 2021-01-30T14:10:48.168100Z

Good morning Clojurians, I am trying to create a diagram of how parts of fulcro work together. Here is what I have, I am looking for some feedback, how can I make it more accurate/better?

❤️ 1
2021-01-30T15:15:19.168700Z

You have defmutation displayed on the frontend side, but not on the backend. Perhaps add that in to the Pathom section to show that mutations exist there as well?

1
tony.kay 2021-01-30T17:46:57.169Z

So remember that mutations all go through mutations

tony.kay 2021-01-30T18:45:04.169200Z

🙌 1
yubrshen 2021-02-01T04:58:45.194900Z

Here is my attempt to do simple typeset for your diagram, with my suggestion using the example of People and Car in the Fulcro 3 tutorials. It looks not very pleasant, but it has the advantage that it's created with text, that we can effectively edit the textual specification to improve it together. Here is the source code:

#+BEGIN_SRC plantuml :exports none :file ./normalization-illustrated.png
@startuml
skinparam linetype polyline
title App State
rectangle "UI" as UI {
circle "root :sample" as root_data
rectangle ":sample"  as sample_table {
        circle ":person/id 3" as person_id_3
        rectangle ":car" as car_table {
                circle ":car/id 22" as car_id_22
                circle ":car/id 42" as car_id_42
                }
        }
}

database "Normalized Data Graph" as DB {
'rectangle "root :sample" as root_data
        rectangle ":person/id" as person_table_n {
                rectangle ":person/id 3" as person_id_3_n
        }
        rectangle ":car/id" as car_table_n {
                rectangle ":car/id 22" as car_id_22_n
                rectangle ":car/id 42" as car_id_42_n
        }
}

UI .right.> DB : UI tree to normalized DB
root_data -down->  person_id_3
'person_table -down-> person_id_3: :person/id 3
'car_table -down-> car_id_22 : :car/id 22
'car_table -down-> car_id_42 : :car/id 42

person_id_3 -down-> car_id_22
person_id_3 -down-> car_id_42

person_id_3_n -down-> car_id_22_n : person/cars
person_id_3_n -down-> car_id_42_n : person/cars

@enduml
#+END_SRC
With your correction/feedback, I can further improve it. (I'm still not quite comfortable with modeling the data in terms of graph yet. My understanding may not be accurate.) I use https://plantuml.com/ to create it with my emacs setup.

tony.kay 2021-02-01T05:21:16.195400Z

Thanks for giving that a try. The main concept I was trying to get across is just that the operations of Fulcro are always centered around some portion of a tree. Sometimes it’s the whole tree, sometimes it is a subtree. But the overall point is that a very small number of core concepts are involved in pretty much everything you do.

tony.kay 2021-02-01T05:21:51.195600Z

I’m not sure what to say about your diagrams. I sorta see what you’re getting at, but they don’t convey what I was trying to get across.

tony.kay 2021-02-01T05:22:28.195800Z

The “dashed lines” for something that doesn’t exist at some point, and stressing manipulation of/with subgraphs was most of what I was trying to talk about

tony.kay 2021-02-01T05:23:29.196Z

mixing in keywords might be helpful somehow…this is really more of a whiteboard discussion/lecture I think, or a presentation with animations 😄

yubrshen 2021-02-01T06:43:44.196600Z

I'll try to express your idea of partial tree of UI elements being absorbed into the normalized tables.

tony.kay 2021-01-30T18:45:28.169600Z

@holyjak

tony.kay 2021-01-30T18:47:50.172Z

That’s basically what’s in my head on those kinds of diagrams. Use dashed lines for elements that you “know the shape of” from the query, but do not yet have in the database. Initial state is just the portion of the UI that goes into client db, and then is turned into a tree for sending to root. Root is only able to render the data it gets. Loads/merge component are just “tacking” new things into the db, and then creating edges (targeting).

🙌 1
tony.kay 2021-01-30T18:49:16.172700Z

The operation of Fulcro is really mostly those three frames. Start, render, put in data, render, put in data, render …

tony.kay 2021-01-30T18:49:39.173200Z

and render is nothing more than “get data from db w/query and pass to root”

tony.kay 2021-01-30T18:50:44.174500Z

Mutations are the missing part from this set of diagrams, because there’s also the “fiddle with db and issue remote updates that can return data”…But a load is just a special internal mutation that has one particular structure

tony.kay 2021-01-30T18:59:54.174600Z

🙌 1
tony.kay 2021-01-30T19:00:10.175200Z

There’s a mutation diagram that might be useful @timofey.sitnikov

Jakub Holý 2021-01-30T19:01:16.175300Z

Sorry, I do not really get this "mutations all go through mutations". You mean that remote Fulcro mutations are sent as EQL mutations?

tony.kay 2021-01-30T19:02:58.175600Z

🙌 1
tony.kay 2021-01-30T19:03:24.176400Z

Technically a mutation can talk to any number of remotes, or a transaction could run some number of mutations each which could talk to any remote.

tony.kay 2021-01-30T19:04:02.177100Z

Fulcro enforces (by default) that writes are prioritized over reads, and that operation is in the order of submission (per remote)

tony.kay 2021-01-30T19:06:15.179100Z

But the diagram of a mutation result is JUST exactly the first diagram for normal operation. A mutations’ returning and with-target indicators (which you say in a remote) allows the remote to return a tree of data that is normalized via the query, with edges created by targeting. It’s all the same thing over again. The big exception is that the action sections of mutations can also do arbitrary manipulation of the normalized db.

tony.kay 2021-01-30T19:07:08.179700Z

So the “return value” story of mutations looks exactly like the “load” and “merge component” cases from diagram 1.

tony.kay 2021-01-30T19:07:34.180300Z

And action sections can use merge-component to do structured data insertion via the exact same mechanism (normalize a tree of data and create join edges).

tony.kay 2021-01-30T19:11:15.183600Z

If you’re using websockets, then a push can send a tree of data, and include a “topic” that names which kind of thing it is. Then merge component can be used to do the same thing: normalize it into the db and create edges….or a push could trigger a mutation. As another side-note: UISM is nothing more than a way to “join together” a bunch of scattered mutations into a more cohesive unit that abstracts the specific UI components away from the logic. An actor in UISM is one of the UI elements as an abstraction. Thus, UISM gives you both a way to unify related logic to a task (i.e. session management) while simultaneously not having to know any specifics of the UI components themselves.

👍 2
tony.kay 2021-01-30T19:13:03.183700Z

that was word salad…not sure what I meant to say…..let me reconstruct it in my head 😜

tony.kay 2021-01-30T19:14:06.183900Z

Yeah, I was commenting on Timofey’s diagram. Remote behavior always involves a mutation….even loads (there’s an internal-load mutation)

👍 2
Jakub Holý 2021-01-30T19:15:21.184200Z

Thanks a lot! I will think about it.

tony.kay 2021-01-30T19:16:09.184500Z

There’s no alternative way to talk to a remote. You issue a mutation through transact (read df/load!…that’s what it does too), the mutation says it has local and remote operations. Everything that changes in Fulcro or talks on the network is a mutation, even internally. (load puts in and clears load markers, locally, then indicates desired remote operation, and uses a different result-action than normal mutations…go read the mutation in the data-fetch ns 🙂 )

👍 1
tony.kay 2021-01-30T19:17:55.185300Z

Yeah, I’d love better formal diagrams, so making some variant of these pretty would be very welcome

👍 1