Some more experiments for upcoming Fulcro 3.5 with respect to raw React usage, and just using hooks and lightweight components in Fulcro in general. The SHA 34789fb993fdfd121d3ffa3551b106b7ae374f8b has the support, and the demo cards. Here’s an overview:
• Refined use-tree
so that it is easier to use with I/O and such. See https://github.com/fulcrologic/fulcro/blob/feature/fulcro-3.5/src/workspaces/com/fulcrologic/fulcro/cards/composition4_cards.cljs#L190
• Made a helper that generates a form-state compatible component from nearly no code: https://github.com/fulcrologic/fulcro/blob/feature/fulcro-3.5/src/workspaces/com/fulcrologic/fulcro/cards/composition4_cards.cljs#L154
• Made a use-uism
that lets a state machine set up actors, and returns the current props for all actors. I think this is the most useful way to do this one, but it sort of implies the UISM will be a parent-like thing to all actors in UI: https://github.com/fulcrologic/fulcro/blob/feature/fulcro-3.5/src/workspaces/com/fulcrologic/fulcro/cards/composition4_cards.cljs#L321
Thanks so much Tony for sharing your innovation with us through Fulcro. The experiments are cool, can't wait to try out the demos. Since fulcro-3.4.21-SNAPSHOT does not contain alpha.raw-components3.cljs, I have cloned the branch feature/fulcro-3.5 from the Fulcro repository. However, after spending hours trying to run the workspaces cards, I still haven't figured out the workflow to launch the workspaces (like the way we do it with Fulcro Template). It would be appreciated if anyone could give me a pointer on what is the best way to run these demo cards.
Shadow, build workspaces, then you have to use /workspaces.html on the non test url
Many thanks @tony.kay for your help! The cards are working perfectly now.
The sc
and formsc
functions are actually a pretty cool idea for super lightweight components (that have no render, only compatible with component-options)…thus you can get query/ident/initial state AND component registry (if you need it) with almost nothing more than a raw EQL query.
I’m attempting to add a RAD report and form to an existing fulcro app. I have a basic table and editor working. Now I’m needing to add a “hidden” query-param to filter the report’s query, but the only way I’m seeing to add query-params is via ro/controls
. Am I missing it? Maybe something like fo/triggers
but for reports …? If I add my own custom key to the defsc-report
map, where’s the best place to process that?
Good morning Clojurians, I am trying to use https://material-ui.com/ in my Fulcro project. After some research, I found the following approach:
(ns app.ui.material-ui
(:require
["@material-ui/core" :as mui]
["@material-ui/core/Button" :default material-button]
[com.fulcrologic.fulcro.algorithms.react-interop :as interop]))
(def button (interop/react-factory material-button))
(def css-base-line (interop/react-factory mui/CssBaseline))
(def app-bar (interop/react-factory mui/AppBar))
Looking at the https://github.com/MrEbbinghaus/fulcro-material-ui-wrapper, the files are not .cljs
but they are .cljc
. Why are they .cljc
? Seems like this is only for the cljs side of things.Controls, just don't add it to the layout.
Yes. It only works for CLJS. BUT. With fulcro itself, you can use components on the server-side as well. (for SSR or initial-state, for example). I figured, it would be nice to provide a cljc so that the user don't have to add reader conditionals in their code, if they wish to use their components on the server-side.
OK, that makes sense.
@mroerni, I do have on more question, how do you turn this example:
<Typography variant="h6" color="inherit" noWrap className={classes.toolbarTitle} >
into CLJS. I tried this:
(material-ui.data-display/typography {:variant "h6" :color "inherit" :className "{classes.toolbarTitle}"}
But I am not sure how to include the noWrap
since it does not have a pair.{:noWrap true
:className "just-a-string"}
:className ["foo" "bar"]
works as well.
{classes.toolbarTitle}
is JSX syntax for string interpolation. The example you’re looking at must have an object called classes
with a property toolbarTitle
in scope somewhere.
@cjsauer, I believe the classes are generated by material UI, but I am not sure.
@mroerni I added that sample to your REAME.md, see if it makes sense to you. It may make it easier for someone like myself to get started. Also, I recommend removing the Warning statement from readme, warning reads to me that the repo can harm something, but it is pretty benign, clean, and nice repo, nothing to warn about.
classes
comes from the custom styling method used in that material-ui example
See:
https://material-ui.com/styles/basics/#hook-api
The warning is there because I created the repo with no one in mind but myself. 🙂 Because of this not all components are included and there are some "breaking changes" (renames/moves).
ok, I have added a control with :type :string
but how do I set the value? This doesn’t work
ro/controls {:agency {:type :string :value "SYRCL"}}
this worked:
:componentDidMount (fn [this]
(control/set-parameter! this :agency "SYRCL"))
You can set it when routing to the report, the fn takes a map of extra params, look into the demo
Hey all 👋
I wanted to quick share an idea I’m toying with that builds on top of Fulcro RAD’s authorization support. It’s mentioned in code comments that the hope is for community members to step up and try to tackle this, so here goes 🙂
https://gist.github.com/cjsauer/9ab075ca995d7ee855040271c766db27
This idea is implemented in two pieces:
- Reads: A pathom plugin that wraps each reader
call and checks whether the logged in user has :read
access for this attribute of https://gist.github.com/cjsauer/9ab075ca995d7ee855040271c766db27#file-authorization-clj-L28-L32. If not, that value is replaced with a :redacted
value, similar to how RAD’s current impl works. Unlike RAD’s current impl tho, which elides unreadable keys as a post-process, this strategy leverages the rich amount of state available during the pathom parse, which for the common cases I tested seems to allow deriving “this entity” automatically. Reads are allowed by default, but this could be configurable.
- Writes: Fulcro form save/delete middleware that scans the form diff to check if the logged in user has :update
/`:create`/`:delete` access for every attribute on every entity in the diff. A save payload is allowed or denied as a unit, rather than succeeding partially. Writes/delete are denied by default, but this could be configured.
With this in place, one can https://gist.github.com/cjsauer/9ab075ca995d7ee855040271c766db27#file-account-cljc-L15-L18`::auth`https://gist.github.com/cjsauer/9ab075ca995d7ee855040271c766db27#file-account-cljc-L15-L18 to configure access controls; it’s a function of (fn [env entity-ident user-ident])
to a set of permissions #{:create :read :update :delete}
.
A lot of the “magic” is possible thanks to metadata on attributes like ao/identities
and ao/identity?
, however I’m certain there are some edge cases that I’m not aware of. Feedback very welcome. Thanks for taking a look.
So, back to the drawing board. I oversimplified things chasing a fact based model. Thanks for your feedback @tony.kay
I think I’ll switch gears to something closer to your resolver/mutation level solution. I’m thinking I could use pathom :transform
function to sprinkle in auth checks, and that those could potentially integrate with RAD’s generated resolvers quite easily.
What I’ve ended up doing in my projects is making defresolver/mutation macros that wrap pathoms, and allow the security declaration on the server pathom unit as a function that receives the pathom env and the inputs. That makes for a fully general permissions system where the middleware can augment the env with things like user permissions, policies, etc…and then the endpoint itself can look basically like this:
(defn admin-only [env input] ...)
(defresolver x [env input]
{:policy admin-only
...})
I don’t have time to look over code right now, but perhaps there is a useful idea in there.Thanks for working on it. I look forward to seeing what you end up with. Integrating with the attributes is of course the right path, and having resolvers generate from defattr with a similar approach is, of course, pretty simple