Clojurians
#untangled
<
2017-02-22
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

tony.kay00:02:37

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

tony.kay00:02:15

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 :wink:

tony.kay00:02:04

At this point (barring bugs and expansion of field types/validation) the forms support should be pretty usable

tony.kay00:02:34

I think I'm done renaming things, at least

macrobartfast01:02:27

is there anything I should know before embarking on https://awkay.github.io/om-tutorial ?

adambros01:02:55

@tony.kay it seems like post-mutations are only used for their :action, but i need it to (maybe) trigger another remote

tony.kay03:02:01

@adambros Hm.

tony.kay03:02:23

@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

macrobartfast03:02:31

ah ok cool, then I'll just do the Untangled dev guide

tony.kay03:02:31

@adambros what is the scenario sequence?

tony.kay06:02:44

proof of concept for the image crop tool is now up in UI. needs some polish, but generally works.

kauko08:02:32

Hmm, this could be a stupid question :slightly_smiling_face: 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.

kauko08:02:49

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 :slightly_smiling_face:

qqq08:02:00

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?

cjmurphy09:02:57

@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.

qqq09:02:05

@cjmurphy : wait, so that's not a typo and I'm really supposed to copy the file to /usr/local/etc/todomvc.edn ?

qqq09:02:19

how does this provide safety? it just seems very very weird

qqq09:02:34

why is this to .a local place relative to project.clj ?

cjmurphy09:02:38

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.

qqq09:02:38

eh, copied it over, this still confuses me to no ned

qqq09:02:16

I will reserve my criticism until I work through the tutorial; after which I"m going ot ask about this again :slightly_smiling_face:

cjmurphy09:02:32

It is going to a standard Unix place for config of applications.

cjmurphy09:02:09

Sure - most of the actual Untangled people are asleep at the moment.

qqq09:02:00

oh man, this is nice

qqq09:02:08

I think I'm already sold

qqq09:02:23

is there any nice way to have the backend use gae or aws instead of datomic?

cjmurphy09:02:15

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.

kauko09:02:27

@cjmurphy any chance you could answer my question above?

cjmurphy10:02:31

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...

cjmurphy10:02:43

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.

kauko10:02:53

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

cjmurphy10:02:03

Another way is to communicate across using Untangled/Om, then still call REST services on the server.

kauko10:02:08

Obviously they CAN work together, but you lose some synergy.

baris14:02:22

@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

baris14:02:52

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.

kauko14:02:08

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

baris14:02:51

For the moment - yes. Maybe in the near feature you can plug your server reads and mutations to vase.

baris14:02:15

Vase is also on my todo list....didn’t had the time to check it out

tony.kay16:02:57

@kauko Security. Yes, that cookbook recipe are my musings on the subject.

tony.kay16:02:09

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

tony.kay16:02:41

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

tony.kay16:02:18

So, you could run a post-query analysis on the graph edges that actually resolved with a permissions check function before returning it

tony.kay16:02:44

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.

tony.kay16:02:05

In practice, the algorithm I just described in 1/2 above is pretty good

kauko16:02:48

Yeah it makes sense to me.

kauko16:02:19

Keeping a white- or blacklist of allowed keys can be a challenge

tony.kay16:02:39

@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.

tony.kay16:02:41

@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)

tony.kay16:02:53

So, REST is totally possible, just more work

kauko16:02:25

Yeah, again, I didn't think that you wouldn't be able to use Untangled with any server :slightly_smiling_face: Or talk to REST endpoints

tony.kay16:02:28

We'll get documentation on the more modular server support in untangled-server soon.

kauko16:02:45

That came out a bit rude, sorry

tony.kay16:02:48

we're using it, just havent doc'd it yet

tony.kay16:02:58

@kauko I didn't take it that way. no worries

kauko16:02:33

:+1: Thought it sounded snappy

tony.kay16:02:46

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

tony.kay16:02:15

and it's so trivial to write the server logic when you're working with EDN

tony.kay16:02:39

so, we write REST when external clients need to hit against it with old tech, but don't hit it ourselves from our SPAs

tony.kay16:02:15

the server-side functions are often so thin it is a waste of time to write converters to try to avoid code duplication

tony.kay16:02:36

it's like..."let's write this REST interpreter to avoid duplicating a line of really simple code here and there"

tony.kay16:02:46

seems like a bad tradeoff

tony.kay16:02:20

and you can share the common query code among the endpoints...so you can still eliminate code duplication

tony.kay16:02:07

but it is tempting to say "I already have the REST...so let's just leverage those"

tony.kay16:02:34

That can work...you don't have to do complicated recursive queries from the UI

tony.kay16:02:54

you can always join up the graph as a post step (post mutation) on the client

tony.kay16:02:33

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

tony.kay16:02:37

all sorts of options

tony.kay16:02:53

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

tony.kay16:02:32

ok...all day meeting I gotta go to. Hope I caught up to everybody :slightly_smiling_face:

urbank18:02:10

I'm confused as to how to tread [:items/by-id 1] as a reference to an entity in a table

urbank18:02:22

so if the state has a list of items

urbank18:02:56

{:list [[:items/by-id 1] [:items/by-id 2]]}

urbank18:02:14

if a parent component queries for this :list

urbank18:02:42

how does the child resolve [:items/by-id 1] to {:item/id 1 :item/name "a name"}

urbank18:02:44

Or am I misunderstanding. Does the child query merely provide a part of the query to the parent?

urbank18:02:39

I'm asking, because I can't seem to make the queries actually provide what I want to the child component

urbank18:02:57

the child is just geting [:items/by-id 1]

urbank19:02:21

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

urbank19:02:58

Root: (query [this] `[:ui/react-key {:workers/table ~(om/get-query WorkersTable)}])

urbank19:02:17

WorkersTable: (query [this] [{:workers (om/get-query WorkerRow)}])

urbank19:02:33

WorkerRow: [:worker/id :worker/first-name :worker/last-name :worker/nick-name]

urbank19:02:41

which would combine into

urbank19:02:53

[{:workers/table [{:workers [:worker/id :worker/first-name :worker/last-name :worker/nick-name]}]}]

urbank19:02:13

where :workers/table is a vector in the app db

urbank19:02:26

a vector of

urbank19:02:53

[[:workers/by-id 1] [:workers/by-id 2]]

macrobartfast20:02:01

I'm really enjoying the devguide... so cool it's done in devcards.

adambros22:02:53

@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)

adambros22:02:17

@baris @kauko @cjmurphy I'll be writing documentation for the new server api (untangled-system and APIHandler) as I wrote it so we could use the image library component in untangled-ui

kenbier22:02:06

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

kenbier22:02:26

I remember I used the Untangled tutorials when they first came out. Are those still good sources?

adambros22:02:03

Pretty sure we've had a whole sprint to updating the documentation, so yes?

qqq22:02:27

the devcards look nice

qqq22:02:40

I started with untangeld yesterday, am working through the devcards now, and they seem very well written.

kenbier22:02:42

awesome, i totally forgot about that @adambros.

adambros22:02:09

There's also awkay/om-tutorial

kenbier22:02:32

@adambros I remember using that as well when it first came out. @qqq did you have any om next experience before this?

kenbier22:02:15

i think ill start him on the untangled tutorial for now. If he wants more ill point him to tony’s tutorial. :slightly_smiling_face:

urbank22:02:41

@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.

urbank22:02:02

You mean (get-query WorkersTable) in root?

urbank22:02:40

The correct Idents get to WorkerRow, but they're just idents ([workers/by-id 1] instead of {:worker/first-name "name" ...})

urbank22:02:07

I might be fundamentally misunderstand what's going on

adambros22:02:49

Can you provide code? and your app state as well?

urbank22:02:25

@adambros Thanks for the help! here's the code http://pastebin.com/abVhgAdF

adambros23:02:39

urbank: for reference you can upload a snippet in slack itself

adambros23:02:57

what is the reason for :workers/table having :workers in it?

adambros23:02:13

eg: why not just {:workers/table [idents…]}

urbank23:02:37

Because I might want to add more fields there later

adambros23:02:53

WorkersTable ident is just [:workers/table]

adambros23:02:59

om idents must be 2 elements

adambros23:02:15

are you coming into untangled with or without om experience?

adambros23:02:16

you may want to follow https://awkay.github.io/om-tutorial/ for learning about om next

adambros23:02:39

it’s not necessary, but i would suggest it while you wait and use it as a reference in the future

urbank23:02:23

Oh nice. I'll definitely read through it.

adambros23:02:56

towards the bottom theres a section on idents

urbank23:02:55

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

urbank23:02:42

Given the code as it currently is

adambros23:02:58

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”}

adambros23:02:20

which seems wrong

adambros23:02:45

ah i think its the WorkersTable ident

urbank23:02:16

Hm... that's weird.

urbank23:02:20

I'm not getting any nils. I'm just getting the map at the beginning of the file I posted

adambros23:02:41

yeah i had to tweak it’s ident

adambros23:02:49

but i cant get it quite right yet

adambros23:02:20

something showed up

adambros23:02:31

not sure im doing it right

urbank23:02:33

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?

urbank23:02:10

Thanks a lot for taking the time to help me out with this, by the way!

adambros23:02:52

yeah basically, it’s the recommended way forwards for initial state

adambros23:02:26

i think that devguide has basically what you are trying to do

adambros23:02:32

person -> worker

adambros23:02:10

notice how PeopleWidget has no query or ident

adambros23:02:39

so key insight, WorkersTable doesn’t need a query or ident, it will just render the :workers it gets passed in

adambros23:02:47

make sure you read all of that devguide section E_UI_Queries_and_State

urbank23:02:32

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

adambros23:02:05

are you wondering about having other keys in your old :workers/table ?

adambros23:02:53

ie: are you asking about how to view the same table in different ways?

urbank23:02:22

Yes! That's actually the thing I most need. A bunch of ways to view and edit some data

adambros23:02:16

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

adambros23:02:58

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