Fork me on GitHub
#untangled
<
2016-06-27
>
curtosis00:06:19

should I be able to render "top-level" queries in nested components? For example, I have a LoadingIndicator component 3 levels deep that I want to respond to :ui/loading-data. I get/respond to it just fine in the Root component, and it looks like I have :ui/loading-data in the queries at all 3 levels, but it's not finding it at all in the 2nd and 3rd-level components.

curtosis00:06:24

any hints for debugging?

cjmurphy00:06:40

@curtosis: I haven't had a chance to use them yet. But if they are all at the top level of your app state (no idents involved) then you should be able to access them as 'links'. The advantage of links is that they can be accessed from any component, no matter how deeply nested it is.

curtosis01:06:33

thanks! I'll take a look. clearly I've got something muddled, so hopefully getting a dose of theory will help.

curtosis12:06:29

well, I thought that made things clearer but now none of my queries work.

curtosis12:06:21

or at least, I can make the top-level query in Root work, but none of the nested ones.

wilkerlucio13:06:59

hello, I might have found a bug on Untangled, I'm trying to do a remote query that has an union query, and it's failing when trying to normalize

wilkerlucio13:06:21

after some inspection I think that some of the query metadata is being lost at some point

wilkerlucio13:06:52

the error I'm getting is Uncaught Error: Union components must implement Ident

wilkerlucio13:06:10

this is my query

wilkerlucio13:06:15

[{:route/data
  [{[:lesson/by-slug "meet-the-metronome"]
    {:lesson.type/video [:lesson/type :lesson/description :youtube/id],
     :lesson.type/playlist [:lesson/type :lesson/description],
     :lesson.type/exercise [:lesson/type :lesson/title]}}]}]

wilkerlucio13:06:29

query result:

wilkerlucio13:06:35

{:route/data
 {[:lesson/by-slug "meet-the-metronome"]
  {:db/table :lesson,
   :db/id 100,
   :lesson/type :lesson.type/video,
   :lesson/description
   "You've probably seen a metronome before.  There are old ones with a pendulum that swings from side to side and new digital ones that beep.  But all of these devices are designed to help you establish a regular and steady beat.  \r\n\r\nSometimes musicians find it useful to practice their playing along with a metronome to make sure that they aren't rushing ahead or lagging behind the beat.  \r\n\r\nAfter lots of practice musicians tend to develop their own internal sense of time and beat which keeps their playing in time. ",
   :youtube/id "ZYLKuoCeBK0"}}}

wilkerlucio13:06:42

I put some logs in Om, when it tries to normalize, the component meta is not present in the query data, that's what makes me think the data is being lost on the way

wilkerlucio13:06:29

and just confirming, my parent element has an ident for the union

cjmurphy13:06:47

Also this syntax is strange: [email protected](om/get-query TopBar)

curtosis13:06:55

@cjmurphy: still doesn't trigger. I'm also concerned that the :ui/app-version query in TopBar also doesn't work.

curtosis13:06:01

(which is just one level down)

curtosis13:06:28

don't I want to include the query for the child component?

cjmurphy13:06:03

You want to join to other components, not bring the keys in which you seem to want to do.

curtosis13:06:03

hmmm. okay... definitely misunderstood something then.

curtosis13:06:10

so when I do this for TopBar it still doesn't trigger for :ui/app-version: (query [this] ['[:ui/app-version _] {:indicator (om/get-query LoadingIndicator)}])

curtosis13:06:37

and this on Root throws an invalid join error: (query [this] `[:ui/react-key :ui/loading-data :ui/app-version {:top-bar (om/get-query TopBar)}])`

cjmurphy13:06:06

For the first thing, is :ui/app-version in your app state when you check it in the Figwheel REPL?

cjmurphy13:06:23

This one here: [{:keys [:ui/loading-data]} (om/props this)]

curtosis13:06:11

well, I fixed that one at least. didn't change the problem, but still. ๐Ÿ˜›

curtosis13:06:01

my app-state from figwheel: {:ui/react-key "ROOT", :ui/app-version "2016.04", :ui/locale "en-US", :ui/loading-data true}

curtosis13:06:49

(I'm manually setting loading-data for testing)

cjmurphy13:06:48

From what I can tell you ought to be able to see :ui/app-version

cjmurphy13:06:11

, from inside your component

curtosis13:06:26

right now my TopBar query is (query [this] ['[:ui/app-version _] {:indicator (om/get-query LoadingIndicator)}])

curtosis13:06:40

what should my Root query be to pull that in correctly?

cjmurphy13:06:56

Root query just a series of joins. No need to do the links I don't think.

cjmurphy13:06:27

So the :indicator join ought to feature in the root query, just as you have it there.

curtosis13:06:26

I have (query [this] [:ui/react-key :ui/loading-data :ui/app-version [email protected](om/get-query TopBar)])` for Root.

cjmurphy13:06:44

Take out :ui/loading-data from the root query, or make it a link.

cjmurphy14:06:44

I honestly don't know if links need to be in the root query. I have them in in my code, but as links.

curtosis14:06:04

well, I'm using :ui/loading-data in the root query as well. (that one works, unless I write it as a link.)

curtosis14:06:57

but that's probably because my escape quoting is a little wonky and it ends up as [:ui/loading-data client.ui/_]

curtosis14:06:21

yeah, doesn't work at all as a link in Root.

cjmurphy14:06:20

(top-bar) - it is not being given any props. You need to have the join keyword and be feeding that to top-bar.

cjmurphy14:06:20

You definitely don't want [email protected] - you should have join keywords.

cjmurphy14:06:03

I realize I'm being quite general rather than specific ๐Ÿ˜œ

curtosis14:06:36

d'oh. okay, I think it's making sense slowly. I got in a weird rabbit hole thinking the queries did the magic... which they kind of do, but still need to pass the info down into the components in render, right?

cjmurphy14:06:44

Yes - joins often indicate going to a different component.

cjmurphy14:06:18

Really you are passing down another list of hashmaps. You could just debug what is coming into root (pprint props), to see what is coming in.

curtosis14:06:25

well, I fixed all those joins and component calls. still no :ui/app-version or loading data.

cjmurphy14:06:08

Can you do another gist that has all the fixes?

cjmurphy14:06:04

The :ui/app-version is a separate problem. You could do a gist with just that in it.

curtosis14:06:40

and now app-version is mysteriously working... ok. gist coming up.

cjmurphy14:06:26

Is loading-data always false? Is that a problem or is that expected?

curtosis14:06:53

it's not always false, no.

cjmurphy14:06:31

Its usually set by Untangled right? And I can't see that you are setting it anywhere.

curtosis14:06:47

right. I'm setting it manually for testing.

curtosis14:06:07

(swap! (om/app-state (:reconciler @client.core/app)) assoc :ui/loading-data true)

cjmurphy14:06:02

What's a specific problem we can look at?

curtosis14:06:43

so... (om/get-query Root) looks right... [:ui/react-key :ui/loading-data :ui/app-version {:topbar [[:ui/app-version _] {:indicator [[:ui/loading-data _]]}]}]

curtosis14:06:36

but props inside TopBar has :ui/app-version but not :ui/loading-data

cjmurphy14:06:11

I would want to see a ' before every link.

cjmurphy14:06:33

I don't know why so perhaps it doesn't matter.

curtosis14:06:18

they're there in the query methods; I think they're just getting dropped by the pretty-print

curtosis14:06:47

(if they aren't quoted, the _ gets namespaced)

cjmurphy14:06:08

Your root query looks okay then. Oh yes thanks.

curtosis14:06:43

revised: the props in Root don't have the subsubprops: {:ui/react-key "foo" :ui/loading-data true, :topbar {:ui/app-version "2016.04"}} (no {:topbar {:indicator ...}})

cjmurphy14:06:36

That's to be expected I believe/think.

curtosis14:06:38

I suppose, but then how does :indicator ever get its props?

cjmurphy14:06:01

When you go to the next components it brings out more data. I'm not 100% sure about this. But I don't think it is a problem that you don't get to see the data all the way to the bottom./

curtosis14:06:33

hm, ok. so focusing then on the fact that TopBar doesn't have :indicator either.

cjmurphy14:06:56

Not sure - but it would be a problem if you were not seeing the prop data in the lower level component where you need to see it.

curtosis14:06:16

right. which is, in fact, the current problem. ๐Ÿ˜•

cjmurphy14:06:07

LoadingIndicator does seem like a pointless component. All it has in it is a link. Seems odd to be joining to a component that does not have leaf keys.

curtosis14:06:06

the idea was that it's a reusable block that I can put anywhere, and it just trips state depending on :ui/loading-data

cjmurphy14:06:10

(leaf keys and or joins as well)

curtosis14:06:54

so in the data tree it's (conceptually) at the top level, but in the component tree it could be anywhere, even multiple places

cjmurphy14:06:16

It doesn't need to be passed prop data, or be joined to. It doesn't have to be in a tree.

cjmurphy14:06:38

Maybe you could just pass it {} as props.

curtosis14:06:34

hm.. then where does it get :ui/loading-data from?

cjmurphy14:06:10

Also you can't join to components that don't have idents.

curtosis14:06:35

that seems more likely to be causing the problem.

curtosis14:06:46

what should the ident be of a component that doesn't have its own data?

cjmurphy14:06:51

Yes ๐Ÿ˜›

curtosis14:06:02

(TopBar doesn't have an ident either, but that seems to be working so far)

cjmurphy14:06:31

But it only has links in it.

cjmurphy14:06:46

There's conflation of a lot of ideas here.

cjmurphy14:06:23

The whole thing is links, so no need for joins or idents.

curtosis14:06:49

but... without joins it doesn't work either?

curtosis14:06:02

joins got :app-version working

cjmurphy14:06:06

So my yes now a no.

cjmurphy14:06:19

in the root?

curtosis14:06:01

(I call it out separately in Root, and it works there as well)

cjmurphy14:06:58

If you call (topbar {}) does that work?

cjmurphy14:06:39

If get rid of join to LoadingIdicator as well?

cjmurphy14:06:10

You shouldn't need joins for links to work. That's the purpose of them really.

curtosis14:06:27

that's what I thought as well.

curtosis14:06:49

I'm fairly confused at this point.

cjmurphy14:06:33

I'm not sure about links being in initial state either.

cjmurphy14:06:08

Initial state is for that component. Whereas links are not tied to any component.

tony.kay14:06:56

@wilkerlucio: Did you figure out your problem?

wilkerlucio14:06:31

@tony.kay: yes, I found a bug into Om ast->query, it doesn't add the component meta back on unions, I'm going to issue a PR with a fix

curtosis14:06:59

I'm only using initial-state to stuff :ui/react-key and :ui/app-version into app-state for me.

curtosis14:06:08

(initial-state on Root)

cjmurphy14:06:00

Fair enough - if you can see app state as it should be then I guess there's no issue there.

curtosis14:06:18

but I agree... links don't seem like they should need props passed down. sort of the point.

tony.kay14:06:55

@curtosis: I'm jumping in without reading everything...but links are not magic...they don't put things in props in arbitrary places

tony.kay14:06:15

The initial query in Om always runs from the Root component as a single query

tony.kay14:06:30

so things have to join together, and you have to pick the bits apart and pass them through

tony.kay14:06:01

I've seen cases where if you have no app state path to a component, then you won't get the state of a component (having only a link query) because db->tree will stop looking deeper when it runs out of state

tony.kay14:06:30

This is an Om-ism. Not certain if it should be considered a bug. There is an easy workaround: make sure the path to the component exists in the graph of the db

tony.kay14:06:43

even if the map itself for the component state is empty

curtosis14:06:22

I see (I think). Via each component having an Ident?

tony.kay14:06:17

ok...just a sec....ident it an orthogonal thing to what I'm saying

tony.kay14:06:23

well, not exactly ortho

tony.kay14:06:27

but not identical ๐Ÿ™‚

tony.kay15:06:34

Yeah, in Root, you've composed in top bar, but it has no initial state. Give it initial state that composes in state from TopBar, which in turn should have initial state that has :indicator, which in turn composes in an empty map

curtosis15:06:56

the jumping-off point is more or less how to make a component that only depends on top-level (link) query data.

curtosis15:06:09

ok, I'll give that a go...

tony.kay15:06:29

right, at the moment, the way queries work, it has to compose to root and have matching state, even if the real data you want to access comes from root via a link

tony.kay15:06:43

the db->tree algorithm stops running the query if it cannot follow a join in the graph db

tony.kay15:06:57

so it never reaches your component with the link

tony.kay15:06:08

This is probably a bug in Om, but the workaround is trivial

tony.kay15:06:22

You could also make TopBar and LoadingIndicator stateless (no queries) and pass the data down to them.

tony.kay15:06:16

That is why I'm not sure it should be considered a "bug" per se. They don't really have data of "their own"...but then the query makes logical sense. Something to discuss on Om channel

curtosis15:06:16

LoadingIndicator at least is probably legitimately stateless

tony.kay15:06:32

I've been bitten by the same thing, of course. which is why the sol'n was "obvious" to me ๐Ÿ˜‰

curtosis15:06:39

naturally. ๐Ÿ˜‰

tony.kay15:06:04

Haven't finished arguing the pros/cons with myself. So I'm not pushing the point.

curtosis15:06:21

fair enough.

curtosis15:06:50

so far not working, but I'm not sure I have initial-state wired correctly yet...

tony.kay15:06:37

you still have to pick apart the state and pass it through in the body of the render

curtosis15:06:49

and in fact I did not. ๐Ÿ™‚

tony.kay15:06:51

oh, I guess you were

tony.kay15:06:56

maybe I missed it

curtosis15:06:58

(TopBar was setting {:topbar ...} in its initial-state, so I got {:topbar {:topbar {:indicator ...}}}

curtosis15:06:07

and now I have spin!

curtosis15:06:48

thanks @cjmurphy and @tony.kay for the extended help! very hard to sort through.

tony.kay15:06:52

I should make a tutorial video on links and mention this particular problem

tony.kay15:06:00

almost everyone is going to hit it

curtosis15:06:25

is there an example in the tutorial code for the stateless version?

cjmurphy15:06:36

The video tutorials are a real help by the way.

tony.kay15:06:39

don't remember ๐Ÿ˜„

tony.kay15:06:51

just drop the queries (move them to the root) and pass the data by hand

curtosis15:06:16

I second that - the video tutorials are fantastic. And I hate the video-ification of documentation.

curtosis15:06:30

that's how helpful they are. ๐Ÿ˜‰

tony.kay15:06:57

@curtosis: wow, I'm flattered. (I'm not much of a video fan myself, but I know others like them...so I'm doing my best to make them useful)

tony.kay15:06:33

My opinion is the trick is to keep them simple, clear, and short

tony.kay15:06:45

I'm shooting for 10-20 mins each

curtosis15:06:13

yeah. one concept = one video helps a lot to maintain mental models of locality.

cjmurphy15:06:17

And the working out where things went wrong is good too. Things like I never would have thought to inspect what's going across the wire using dev console. Can only get that sort of thing from videos.

tony.kay15:06:22

Right...making mistakes on video. I don't edit those out for exactly that reason

tony.kay15:06:32

though I did have to pause one cause I got stuck for like 10 mins ๐Ÿ˜œ

tony.kay15:06:40

(the union one)

curtosis15:06:45

yes. that is especially helpful.

tony.kay15:06:05

confused the crap out of myself with the rename

tony.kay15:06:47

@cjmurphy: now if we just had a "transit viewer" for chrome

tony.kay15:06:02

the de-duping in transit makes that stuff kinda hard to read

curtosis15:06:12

just tried making LoadingIndicator stateless, fwiw. Works fine (I put '[:ui/loading-data _] in TopBar's query, then just passed its value in a straight map. LoadingIndicator now has no initial state or query of its own.)

curtosis15:06:52

pro: LoadingIndicator is simpler; parent doesn't need to compose in initial-state and query. con: its parent needs to know that it needs :ui/loading-data, rather than just composing in the query and initial-state.

cjmurphy15:06:16

Sounds good - not a part of Om Next at all.

curtosis15:06:04

all of which is pretty obvious, but still worth calling out explicitly. there's a reason the composability of component queries is helpful. ๐Ÿ˜›

curtosis15:06:58

the deeper reason for trying to sort all this out, of course, is that NavBar (which I've elided here) needs to drive the "tab" switching and reflect the switched-in tab state, so it's all related.

curtosis15:06:50

does untangled eschew component-local state? thinking here of things like click-to-expand submenus.

cjmurphy15:06:23

Its eschewed I guess but makes sense sometimes - like a transact for every single keypress seems to much to me. You can do it if you want to of course.

curtosis15:06:48

if you really need to do per-keypress undo, for example

curtosis15:06:10

not sure it makes sense to replay/undo expand/collapse actions ๐Ÿ˜›

curtosis15:06:21

but in some contexts, maybe.

curtosis15:06:33

(now I have to go back to the om docs and try to remember how to do local state... ๐Ÿ˜‰ )

tony.kay15:06:54

I only do component local state for form entry of text field...and then not always then. Support viewer is much more usable if you can see the user navigating the app

tony.kay15:06:53

I've toyed with making it possible to elide transactions from history with some kind of metadata marker.

tony.kay15:06:29

some kind of marker like ":unimportant" and then any adjacent unimportant history entry simply overwrites it. Automatically compressing adjacent unimportant entries down to one. That way you could do everything the same way, and choose what to elide from recorded history

tony.kay15:06:15

I also want to start hanging network results (and errors) onto history entries so they can be shown in support viewer

tony.kay15:06:29

lots to do still ๐Ÿ˜‰

tony.kay15:06:14

Also need to compress (with something like data differ) the history so that support requests with history are reasonable on bandwidth.

curtosis16:06:57

heh... that makes sense. I may switch them to full transactions later.

tony.kay17:06:10

I've just pushed an update to the Untangled tutorial: Section F-Untangled-Initial-App-State covers the new initial app state, including union support.

tony.kay17:06:47

online version:

tony.kay17:06:34

Online version has a couple of fixes, too. 3 SVG files were missing in the old version

tony.kay17:06:29

BTW: online tutorial is using advanced optimizations on closure with Om and D3. Does a nice job of making a relatively small SPA: 1.4MB

tony.kay17:06:08

Yeah, and that includes 200k of raw text content that cannot be "compressed" through renaming or elision

curtosis20:06:03

any tips for debugging tab switching? I'm seeing the new value show up in app-state under :tabs but the Switcher itself isn't re-rendering the new panel

tony.kay20:06:38

Only tip I have is to A-B compare with the getting-started video code (tabs-union tag)

curtosis20:06:52

sigh. I was afraid of that. ๐Ÿ˜‰

curtosis20:06:06

can't see a diff in the relevant code.

tony.kay20:06:14

make sure you didn't make the same mistake as I did: naming idents using keywords that are also top-level keys

curtosis20:06:33

should both tabs show up in :om.next/tables ?

tony.kay20:06:39

e.g. :tabs as your top-level state key, but also as an ident key...causes the table to overwrite the state

tony.kay20:06:57

I think the om.next/tables thing is an unused vestige

tony.kay21:06:07

The good news is the pattern is well established in code. It is a little tricky to understand at first, but the only real mistakes you can easily make have to do with naming things. Make sure your ident uses the keyword first (and that the keyword in the ident matches the table name of the table holding the thing you're trying to point to)...that keyword is also what you switch the UI on

tony.kay21:06:39

other than that, accidental name collisions can bite you

curtosis21:06:48

so far doesn't look like a name collision... if I put in some dom/buttons at the Root level to transact the tab switch, it works fine. so it must be something in how I'm calling the transact from the nav menu? maybe?

curtosis21:06:06

it almost looks like calling transact! from anywhere outside root isn't triggering Switcher to re-render.

curtosis21:06:34

the only thing I can think of is maybe something in the way I'm setting initial-state to include my work from earlier today.

tony.kay21:06:42

Ah, have you not read/watched stuff on UI refresh?

curtosis21:06:53

somehow react/om isn't getting the wiring

curtosis21:06:02

I have ... but apparently I'm missing something? ๐Ÿ˜‰

tony.kay21:06:04

UI refresh is not completely automatic

curtosis21:06:43

it's been a bit of a firehose this weekend ๐Ÿ™‚

tony.kay21:06:46

If you're trying to get a sibling to refresh on a transact, you'll have to use follow-on reads. If you want a parent to refresh,you should use transact in the parent, and pass a callback of that into the child for triggering

tony.kay21:06:06

Om automatically refreshes the subtree of the transact

curtosis21:06:07

aaah.... that's vaguely ringing a bell

tony.kay21:06:11

other components require follow-on reads

curtosis21:06:24

(transact takes this, after all)

tony.kay21:06:35

right...and that is what is guaranteed to refresh

tony.kay21:06:50

everything else is an index lookup of keywords in the follow-on reads

curtosis21:06:02

dangit. it's so close to magic I expect it to magically work. ๐Ÿ˜‰

tony.kay21:06:02

so it can be abstract on the data

curtosis21:06:11

this seems to be the one video I didn't watch facepalm

curtosis21:06:24

aaand solved. thanks!

curtosis21:06:14

there is much value in "oh, I recognize that problem." and again, very much additional value in ".. and here's a video addressing specifically what causes that problem."

curtosis21:06:54

the one sort of unintuitive bit is that I have it do a follow-on read of :tabs, which is what the thunk changes... but Switcher doesn't query for :tabs

tony.kay21:06:14

Switcher isn't a real UI component

tony.kay21:06:25

it is an artifact needed for union to work

curtosis21:06:53

what makes it "not real" - the union query?

tony.kay21:06:08

just a proxy decision maker...it uses the queries of the children, and the renderers of the children

tony.kay21:06:12

to-one unions like this are a bit of an oddity

tony.kay21:06:21

but a very useful oddity

curtosis21:06:39

I suppose :tabs works to trigger the refresh because in root it gets the Switcher's query, which in turns gets the tabs' queries, which themselves get :type, which is what Switcher renders based on. Do I have that chain reasonably correct?

tony.kay21:06:29

It isn't quite that complicated. When you say :tabs as a follow-on read: Om looks up every component that mentions :tabs in a query, and re-renders them all.

tony.kay21:06:51

Those components explicitly try to re-render their children

curtosis21:06:06

ah, so it's re-rendering Root &children.

tony.kay21:06:14

Om short-circuits the rendering of any whose data has not changed

tony.kay21:06:42

When your UI goes on the screen, Om indexes every on-screen component by the keywords in its query

tony.kay21:06:53

and it keeps that index up-to-date on refreshes

tony.kay21:06:00

"follow-on reads" are just index lookups

tony.kay21:06:48

the nice thing is you don't have to care which components need refresh...you just need to name the bits of the graph that are affected

tony.kay21:06:16

in this case, conceptually, the :tabs bit of the graph now points elsewhere

tony.kay21:06:30

We all want to know "how it works", so it is nice to know the index bits and such...but the real power is that it frees you from having to think about the UI structure. Everything you do (mutation and refresh) is based on reasoning in the graph

curtosis21:06:02

right. In this case, we're changing :tabs so we probably do want to re-render all the children; it wouldn't make sense necessarily to just flag :type as having changed (or so it seems to me)

tony.kay21:06:37

right, type is something you needed to query, but it isn't the part of the graph that changed

curtosis21:06:59

makes sense. (tentatively. ๐Ÿ˜‰ )

tony.kay21:06:00

The before and after of the graph is that the ident under :tabs changed

curtosis21:06:15

re my comment/question about "what makes Switcher 'not real'" => I realized it was a question for me b/c my Switcher is a real component; it renders some html divs around the tab. There's no magic that makes a Switcher "not real" other than not doing its own rendering/queries.

curtosis21:06:44

there's some tricky stuff to wrap your head around initially, but I think I'm finally getting to the point where I'm seeing the clarity of reasoning it enables.

curtosis22:06:58

=> broad thanks for the superb framework and outstanding documentation videos.

currentoor22:06:49

So if I wanted to use xhr requests for most of my remote mutations and reads but also supplement them with some server side pushes using sente, any recommendations?

currentoor22:06:24

It looks like the untantled-websockets library makes me pick xhr XOR websockets?

tony.kay22:06:50

the websockets library handles both remote mutation, reads, and push when you use it. Since it reduces the total number of connections needed, I'd use it. @mahinshaw wrote that library, so perhaps he can comment.

tony.kay22:06:26

As far as I rmember, it does take over the network plumbing on the client

tony.kay22:06:53

The server will respond to either (since both pipelines are still installed).

tony.kay22:06:06

But if you already have a websocket, why open additonal XHR connections?

mahinshaw22:06:09

untangled websockets uses websockets only

currentoor22:06:06

@mahinshaw: reading your code now, looks really nice!

mahinshaw22:06:09

there are no xhr requests. You could put that on a side band, but there is no need. Mutations and reads, as well as push all go through the same plumbinbg

currentoor22:06:49

i figured we might want to reads to go through xhr so we can still leverage http caching, at the browser level

mahinshaw22:06:17

yeah, there is no http caching story there

mahinshaw22:06:45

the nice thing is the websockets are another endpoint, so you can still hit the api endpoint that you are used to

tony.kay22:06:29

To get that going in the same app, I think you'd have to have multiple remote support, which is not there yet. Unless you're using XHR directly

mahinshaw22:06:46

the problem though is reads and mutates will still go through the websocket by default since we override the networking, but you can do ajax

tony.kay22:06:50

is that right Mark?

mahinshaw22:06:08

your right tony

currentoor22:06:27

what if i write my own networking component that wraps both the websockets one and the regular /api one? then my component just decides who to pass the request off to?

currentoor22:06:42

is that feasible?

tony.kay22:06:51

So, it would not be a ton of work to support multiple remotes, and have each use it's own networking stack. That would give you both. Mutations would then say :my-remote true instead of just :remote true....each remote would have it's own key

tony.kay22:06:16

This is a standard feature of Om, which we don't currently hook into

tony.kay22:06:38

the networking queue would have to be fixed up to not be a singleton

mahinshaw22:06:46

I think we would need to patch the network layer (on the client) for that

mahinshaw22:06:26

It could be done in the websockets layer. Which may be a good place to experiment

tony.kay22:06:42

Nah, be much better as true multiple remote support

tony.kay22:06:44

which we need (or want) anyhow

mahinshaw22:06:24

so the client network could just be a map of network components then

tony.kay22:06:32

browser limitations on connections could get a little dicey if you, say, wanted multiple websocket remotes...but whatever

mahinshaw22:06:53

I really donโ€™t think that would be too hard

tony.kay22:06:02

no, it really isn't

tony.kay22:06:18

like I was saying...the main issue is the network queue...it is currently a singleton

tony.kay22:06:30

so each network component would need it's own queue

mahinshaw22:06:45

thatโ€™s fine. they do at the moment anyways

tony.kay22:06:10

you mean we already changed each to have a private queue?

tony.kay22:06:18

I don't remember doing that

mahinshaw22:06:32

yeah, each queue is part of the network component in the client

tony.kay22:06:45

oh...did I do that, or you?

mahinshaw22:06:56

itโ€™s always been that way

mahinshaw22:06:16

I donโ€™t use any of the networking code (for the most part) in untangled client.

tony.kay22:06:30

oh, so I must have already fixed that

mahinshaw22:06:38

actually, I need to revisit that, one sec

mahinshaw22:06:50

right, the queue lives in the implementation of UntangledNetwork/send, and websockets has a different implementation

tony.kay22:06:38

so in that case it probably is pretty simple. Just a matter of some wiring

mahinshaw22:06:12

I was wrong, itโ€™s one queue that pushes to send

mahinshaw22:06:17

so there is more work

tony.kay22:06:21

ok, that was my memory

mahinshaw22:06:40

server-send in application.cljs

mahinshaw22:06:13

but that shouldnโ€™t be too bad, since we are using core async. we just need a router.

currentoor22:06:14

but if I'm only going to use websockets for pushes, do you think it's a bad idea to avoid a networking component altogether, just have a separate component that opens a websockets, listens for pushes (mutation literals from the server), and transacts them into the untantled-app

currentoor22:06:22

does that sound like an unwise thing to do?

tony.kay22:06:04

It is only unwise in that browses limit the total number of connections (browser-wide) to a domain

tony.kay22:06:22

so, if you expect ppl to open more than one tab you're possibly asking for trouble sooner

tony.kay22:06:47

but that is no different than having multiple remotes with one being a websocket

currentoor22:06:40

i see, thanks. well two connections seems acceptable IMO. it would be nice to get a google docs like functionality in our app

currentoor22:06:42

since most of the things in our app are dashboards shared between users

curtosis23:06:11

does the om.next logger get a little confused by tab switching?

tony.kay23:06:30

Don't see how it could

curtosis23:06:52

I keep seeing this in my logs:

[1574.490s] [om.next] transacted '[(app/choose-tab {:tab :settings-tab}) {:tabs {:dashboard-tab [:id :type :extra], :settings-tab [:id :type :args]}}], #uuid "e80e791a-fa49-4aa9-aeb3-15ac20a653d3"

curtosis23:06:09

the {:tabs {:dashboard-tab ...} is always the same.

tony.kay23:06:13

the follow-on read gets turned into a query

tony.kay23:06:19

that is normal

tony.kay23:06:48

you say :tabs, Om looks up the component in the index, gets it's query, and adds that to the transaction as the actual read to run

curtosis23:06:37

oh, duh. I was just seeing that :dashboard-tab was always there and didn't notice that it was the full query. operator error .... a good sign I've been at the keyboard too long today. ๐Ÿ˜›

jasonjckn23:06:16

any suggestions for what composes with untangled-server to get user authorization, and limit what mutations are allowed

jasonjckn23:06:24

am looking at cemerick/friend

tony.kay23:06:20

There is a bit on what we do in the Untangled cookbook

tony.kay23:06:37

but that is more for queries

tony.kay23:06:59

mutations...not much out of the ordinary there. Up to you to figure it out.

jasonjckn23:06:14

yah well i'm not sure how well cemerick/friend composes with http-kit

jasonjckn23:06:30

i guess it's more an http-kit question

tony.kay23:06:46

FYI, those using old-style app state (not new app state). There was a bug in new code that breaks code with unions that are NOT using the new app state mechanism. Fixed in 0.5.4-SNAPSHOT, which I just pushed

tony.kay23:06:52

@jasonjckn: yeah, sorry, can't answer that

tony.kay23:06:16

Any ring thing can be plugged into pre or post hook area of U.S.