For anyone interested ( @darrellesh @baris @torkan ) in the forms support: I just pushed an update to develop and clojars. There are now several devcards in the guide that explain form support. The Whole Form Logic page in the guide in particular has a fun example: building a form that uses remoting to check if a username is in use
it simulates the server in the browser, but the code is exactly as you'd write it with a real server. Just run the server stuff in a clj server instead π
At this point (barring bugs and expansion of field types/validation) the forms support should be pretty usable
I think I'm done renaming things, at least
is there anything I should know before embarking on https://awkay.github.io/om-tutorial ?
@tony.kay it seems like post-mutations are only used for their :action, but i need it to (maybe) trigger another remote
@adambros Hm.
@macrobartfast that the Untangled dev guide is basically that, but expanded. I have not maintained the om tutorial much. If you're going to use Untangled, then ignore it
ah ok cool, then I'll just do the Untangled dev guide
@adambros what is the scenario sequence?
proof of concept for the image crop tool is now up in UI. needs some polish, but generally works.
Hmm, this could be a stupid question π I understand one of the advantages of Untangled + Untangled-server + Datomic (or you know, just Om + Datomic..) is that you can use the same queries and mutations on the client and on the server. From the examples it looks like the client just sends the queries it wants to the server, and apparently the server just.. executes them? What about security? I skimmed through the tutorial and the dev guide, but couldn't find anything to answer this question.
I was actually thinking whether an Untangled client would work well with Vase microservices. There's a bunch of stuff that the untangled-server does, but I didn't see a reason why Vase couldn't be extended to do these things also. One problem I do see that Vase seems to be meant for creating REST APIs, whereas Untangled-server doesn't look too RESTy to me π
https://github.com/untangled-web/untangled-todomvc <-- is there a typo in the first line?
Copy resources/config/defaults.edn to /usr/local/etc/todomvc.edn.
^^ wtf why am I copying something to a blocal path?@qqq: That's a safety/deployment thing, so that tutorial type code never overrides production code. You will find that apart from that there isn't any low level copying around of files.
@cjmurphy : wait, so that's not a typo and I'm really supposed to copy the file to /usr/local/etc/todomvc.edn ?
how does this provide safety? it just seems very very weird
why is this to .a local place relative to project.clj ?
Yes - its like a standard so nothing bad ever happens - as Untangled is a framework - it does alot, but you don't want it to do alot in the wrong place.
eh, copied it over, this still confuses me to no ned
I will reserve my criticism until I work through the tutorial; after which I"m going ot ask about this again π
It is going to a standard Unix place for config of applications.
Sure - most of the actual Untangled people are asleep at the moment.
oh man, this is nice
I think I'm already sold
is there any nice way to have the backend use gae or aws instead of datomic?
It is simple data structures that are passed back and forth, so you can go against s/thing other than Datomic yes. I've only written against an existing server.
@cjmurphy any chance you could answer my question above?
Auth (both types) has always been a hazy subject for me with Untangled. I compare it to Sente where (IIRC) the example you follow (use as a template) has a login screen and, and uses some Auth library to help. I'm just about to go through the Cookbook recipies - there is one called server-query-security. I understand that some users have not specifically used Untangled for Auth. Its something I too am looking for leadership on...
https://github.com/untangled-web/untangled-cookbook/tree/master/recipes/server-query-security this one?
As far as using something that is RESTy - yes just use Untangled Client, and talk across like any web client - that's what I did - the application is really a Untangled/Sente one, which is quite close to being an Om/Sente one.
Yeah about the Vase thing.. I brought that up because like I said, I was looking into the possibility of using Vase and an Untangled client together. But to me it seems like an Untangled client works really well with a server that can just accept incoming queries and mutations, and Vase seems to be meant for exposing Datomic queries through a REST API
Another way is to communicate across using Untangled/Om, then still call REST services on the server.
Obviously they CAN work together, but you lose some synergy.
@kauko you can run vase with an untangled server support. The new server module-system makes it possible to run your own web-server, middleware etc. So itβs possible to use vase with pedestral for exposing your data as a web-service to other consumers. Furthermore you can run an untangled client aside. Checkout the docs in the source code
https://github.com/untangled-web/untangled-server/blob/master/src/untangled/server/core.clj#L215
The untangled client communicates at the "/api/" endpoint by default and do a lot of network plumbing stuff. You need to implement the server reads and writes.
So yeah, if I understand you correctly, my thinking was correct. Vase solves a different kind of problem, it doesn't really apply to Untangled. Like you said, it's good for exposing data for other consumers, but I'd probably want to have a different endpoint for my untangled client
For the moment - yes. Maybe in the near feature you can plug your server reads and mutations to vase.
Vase is also on my todo list....didnβt had the time to check it out
@kauko Security. Yes, that cookbook recipe are my musings on the subject.
Your query will always be "rooted". e.g. you're going to combine session info with the query to figure out where to start. From there you are following a graph. So, a query is allowed if: 1. The user is allowed to read the root entity of the query 2. AND there appear no keywords in the query that follow references that the user is not allowed to traverse
That is not foolproof, but the exceptions are relatively simple...there might be cases where you have to do more than just check the keywords are in a whitelist
So, you could run a post-query analysis on the graph edges that actually resolved with a permissions check function before returning it
same problem with any kind of client-based query language. Using SQL with Untangled isn't bad (we're doing it, now too). The security issue is the same: if you allow the UI to generate the query, you get great power, but you have to solve the security issue.
In practice, the algorithm I just described in 1/2 above is pretty good
Yeah it makes sense to me.
Keeping a white- or blacklist of allowed keys can be a challenge
@qqq as cjmurphy said: this is meant to be a production framework. You would not want to accidentally start a development mode config on a production server...might seed data, etc. Bad news. You CAN run without the copy, with a command line option that tells it to use an internal config...but you have to be explicit.
@kauko On synergy: You can plug in your own network object in untangled client and talk to whatever. You'd just transform the EDN to whatever request you want to make, then transform the response into the right shape. That, in fact, is what I do in a lot of the full-stack examples to simulate a server using the browser (I hook in networking that just calls js functions instead of doing networking)
So, REST is totally possible, just more work
Yeah, again, I didn't think that you wouldn't be able to use Untangled with any server π Or talk to REST endpoints
We'll get documentation on the more modular server support in untangled-server soon.
That came out a bit rude, sorry
we're using it, just havent doc'd it yet
@kauko I didn't take it that way. no worries
π Thought it sounded snappy
Part of the advantage of Untangled is you get the plumbing for Om without having to write it. As soon as you go to REST you're losing half of the goodness
Yeah
and it's so trivial to write the server logic when you're working with EDN
so, we write REST when external clients need to hit against it with old tech, but don't hit it ourselves from our SPAs
the server-side functions are often so thin it is a waste of time to write converters to try to avoid code duplication
it's like..."let's write this REST interpreter to avoid duplicating a line of really simple code here and there"
seems like a bad tradeoff
and you can share the common query code among the endpoints...so you can still eliminate code duplication
but it is tempting to say "I already have the REST...so let's just leverage those"
That can work...you don't have to do complicated recursive queries from the UI
you can always join up the graph as a post step (post mutation) on the client
so, just query the entities (with something you can detect as the desired graph edge, like the FK value), get them in the db, them hook em together by rewriting the FK ID into idents
all sorts of options
for that matter, as long as the "graph" returned from REST can be trivially converted to EDN and normalized by Om...it really isn't that hard. Who says you have to parse the UI query? Just blindly respond with the "right thing" when you see a certain kind of query
ok...all day meeting I gotta go to. Hope I caught up to everybody π
I'm confused as to how to tread [:items/by-id 1] as a reference to an entity in a table
so if the state has a list of items
{:list [[:items/by-id 1] [:items/by-id 2]]}
if a parent component queries for this :list
how does the child resolve [:items/by-id 1] to {:item/id 1 :item/name "a name"}
Or am I misunderstanding. Does the child query merely provide a part of the query to the parent?
I'm asking, because I can't seem to make the queries actually provide what I want to the child component
the child is just geting [:items/by-id 1]
The queries of my components from the root down combine into a query which does return what I want when run through om/db->tree, yet doesn't work in the actual ui
Root: (query [this] `[:ui/react-key {:workers/table ~(om/get-query WorkersTable)}])
WorkersTable: (query [this] [{:workers (om/get-query WorkerRow)}])
WorkerRow: [:worker/id :worker/first-name :worker/last-name :worker/nick-name]
which would combine into
[{:workers/table [{:workers [:worker/id :worker/first-name :worker/last-name :worker/nick-name]}]}]
where :workers/table is a vector in the app db
a vector of
[[:workers/by-id 1] [:workers/by-id 2]]
I'm really enjoying the devguide... so cool it's done in devcards.
@urbank is your WorkersTable correct? There's no syntax quote and you are putting it under just workers? Aside from that sprinkle prints in your UI graph to tell where the data is failing, and make sure you are using the real app-state and root query (ie call get query on root)
are there any good tutorials for Om Next/Untangled that are up to date? we just had a new hire join and I am looking to get him familiar with both. He has React and some clj experience
I remember I used the Untangled tutorials when they first came out. Are those still good sources?
Pretty sure we've had a whole sprint to updating the documentation, so yes?
the devcards look nice
I started with untangeld yesterday, am working through the devcards now, and they seem very well written.
awesome, i totally forgot about that @adambros.
There's also awkay/om-tutorial
i think ill start him on the untangled tutorial for now. If he wants more ill point him to tonyβs tutorial. π
@adambros Well :workers is the field under :workers/table that holds the worker idents. I added the syntax quote (though I'm not exactly sure why it needs to be there). Also, (om/get-query Component) returns nil in the repl.
You mean (get-query WorkersTable) in root?
The correct Idents get to WorkerRow, but they're just idents ([workers/by-id 1] instead of {:worker/first-name "name" ...})
I might be fundamentally misunderstand what's going on
Can you provide code? and your app state as well?
@adambros Thanks for the help! here's the code http://pastebin.com/abVhgAdF
urbank: for reference you can upload a snippet in slack itself
what is the reason for :workers/table having :workers in it?
eg: why not just {:workers/table [identsβ¦]}
Because I might want to add more fields there later
WorkersTable ident is just [:workers/table]
om idents must be 2 elements
are you coming into untangled with or without om experience?
Without
ah ok
you may want to follow https://awkay.github.io/om-tutorial/ for learning about om next
itβs not necessary, but i would suggest it while you wait and use it as a reference in the future
Oh nice. I'll definitely read through it.
https://awkay.github.io/om-tutorial/#!/om_tutorial.D_Queries
towards the bottom theres a section on idents
Right... so a top level table and the id. I thought that since :workers/table was a top level key, it could be used as an Ident. A bit pointless, but I put it there for some reason. But I'm under the impression that it doesn't really change anything if that ident is there or not, in the WorkersTable component
Given the code as it currently is
so im running your app and when i look at the app state:
@(om/app-state (:reconciler @urbank.core/app))
=> {:ui/react-key "58ae1c49-49a8-4ba7-a268-96549e03ada6", :workers/by-id {nil {:workers/by-id 5}}, :workers/table {:single
ton {:workers [[:workers/by-id nil] [:workers/by-id nil] [:workers/by-id nil] [:workers/by-id nil] [:workers/by-id nil]
]}}, :ui/locale βen-USβ}
which seems wrong
ah i think its the WorkersTable ident
Hm... that's weird.
I'm not getting any nils. I'm just getting the map at the beginning of the file I posted
yeah i had to tweak itβs ident
but i cant get it quite right yet
aha
something showed up
not sure im doing it right
Hm. Interesting. I'll try it on my end. I suppose the InitialAppState is equivalent to just having that in the initial atom that gets passed to untangled?
Thanks a lot for taking the time to help me out with this, by the way!
http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.E_UI_Queries_and_State
yeah basically, itβs the recommended way forwards for initial state
i think that devguide has basically what you are trying to do
person -> worker
notice how PeopleWidget has no query or ident
so key insight, WorkersTable doesnβt need a query or ident, it will just render the :workers
it gets passed in
make sure you read all of that devguide section E_UI_Queries_and_State
Right. In this case this is great. I wonder though if I'll run in to a similar problem later down the line, where this isn't a solution. Will definitely read the devguides
are you wondering about having other keys in your old :workers/table ?
ie: are you asking about how to view the same table in different ways?
Yes! That's actually the thing I most need. A bunch of ways to view and edit some data
well so the idea is that all your data is under :workers/by-id, if you need different views on the same data, you just need to query WorkersRow with a different join key and render them however you need to
om will take care of de-normalizing the data, itβs your job to filter/map/reduce that data until it looks like what you need it to