Fork me on GitHub
#hyperfiddle
<
2023-10-31
>
Dustin Getz01:10:10

Leo’s next talk - Tues 10/31. about situated programs, what is the central problem, and how missionary solved it

🎃 2
💯 3
henrik14:10:58

I’m looking for a general way to fake a causal relationship between sibling graph nodes. Here’s my attempt:

(defmacro cause
  "Fake a sequential causal relationship over `forms`."
  [& forms]
  (let [[form & forms] forms]
    (if (seq forms)
      `(case ~form
         (cause ~@forms))
      form)))
Is this alright?

Dustin Getz14:10:44

1- Don't macro this, we do not promise to keep this working. Write it out each time 2- we want to understand what circumstance you're encountering that makes you reach for this, so we can solve it in a better way

Dustin Getz14:10:28

Search "causal" for past discussions

henrik14:10:04

Basically just flipping some CSS classes.

(cause
  (reset! processing-atom true)
  (transact-some-stuff-to-server …)
  (reset! processing-atom false))

Dustin Getz14:10:16

(catch Pending e (dom/style {:background-color "yellow"}))

henrik14:10:58

The stuff I need to control sits in an awkward place, which is why I’m proxying status to an atom. Will true in the try and false in a finally do the trick?

Dustin Getz14:10:21

i'm not sure that finally makes sense in electric

Dustin Getz14:10:52

you can e/on-unmount in the catch body

henrik14:10:23

Ah, that might be better then. I’ll give it a whirl.

henrik14:10:02

This does not work:

(try
  (reset! processing-atom true)
  (when-let [atom-ident (e/server (e/offload #(create-new-atom node current-space prototype account)))]
    (router/route-to-entity! atom-ident))
  (catch Pending _
    (e/on-unmount #(reset! processing-atom false))))

Dustin Getz14:10:50

first, put the reset! inside the pending body

Dustin Getz14:10:18

i dont know why it doesn't work though

Dustin Getz14:10:51

(let [load-state (try (e/server ...) ::done (catch Pending _ ::pending))] ...) is maybe a useful idiom

👍 1
henrik14:10:06

More context:

(dom/on "click"
  (e/fn [_evt]
    (try
      (when-let [atom-ident (e/server (e/offload #(create-new-atom node current-space prototype account)))]
        (router/route-to-entity! atom-ident))
      (catch Pending _
        (reset! processing-atom true)
        (e/on-unmount #(reset! processing-atom false))))))

henrik14:10:21

This sets the atom to false initially, but does nothing else, it seems.

(e/fn [_evt]
  (reset! processing-atom
    (try (e/server (e/offload #(create-new-atom node current-space prototype account)))
      false
      (catch Pending _ true))))

Dustin Getz14:10:22

try outside of dom/on (we don’t like dom/on it is dying after differential electric lands)

henrik14:10:31

This works:

(case (helpers/on! "click")
  (reset! processing-atom
    (try (e/server (e/offload #(create-new-atom node current-space prototype account)))
      false
      (catch Pending _ true))))
Where helpers/on! is:
(defmacro on!
  ([type]
   `(nil->pending (dom/on! ~type identity)))
  ([type f]
   `(nil->pending (dom/on! ~type ~f))))
It doesn’t work twice though, after it’s run the first time, it dies. If I don’t init with pending, it’ll run on app boot.

henrik14:10:37

I think maybe a couple of nested case is a more pragmatic approach at the moment.

Dustin Getz15:10:01

what is "dies"

Dustin Getz15:10:04

what is "nil->pending"

henrik15:10:07

nil->pending: (if (nil? value) (Failure. (Pending.)) value)

Dustin Getz15:10:14

i dont understand why you would artifically throw pending here

Dustin Getz15:10:36

and (Failure. (Pending.)) is i think not what you want it to be. You need to throw

henrik15:10:44

Right, I’m reaching the limits of my understanding here. The goal is just to prevent triggering the else case of case on boot, after putting the work outside of on!.

Dustin Getz15:10:24

(when click-event ...) ?

henrik15:10:41

Oh yeah, I’m over engineering

henrik15:10:04

Like the one above, this works, but only once. The true branch of when won’t execute again for another truthy value, I presume.

(when (dom/on! "click" identity)
  (reset! processing-atom
    (try (e/server (e/offload #(create-new-atom node current-space prototype account)))
      false
      (catch Pending _ true))))

xificurC16:10:50

dom/on manages the pending, if you catch it and don't rethrow it'll do weird stuff. I think you want

dom/on click
  reset! atom true
  e/server ...
  e/on-unmount reset! atom false

👍 2
xificurC16:10:55

No try catch

henrik16:10:00

Nice, I’ll skip the case stuff then. I’m a little bit disappointed that I couldn’t get the “inverted” layout to work. But I’ve been there and failed previously as well.

xificurC18:10:21

I think ui5 will solve that. Until then we have to stick with what works

👍 2
pez16:10:10

Is this just how the queue behaves? (I’m guessing I am tapping an empty queue?)

Dustin Getz16:10:18

there's a special calva command happening here right?

Dustin Getz16:10:26

run it line by line (tap becomes println), or run the whole test

Dustin Getz16:10:32

i'm not sure what you're seeing, i will try to find out

Dustin Getz16:10:07

running partial tests with the special calva command is going to leak processes, you must cancel each process

🙏 1
pez16:10:10

Yeah, if run them one by one or all of them, then it behaves as I expected.

Daniel Jomphe17:10:14

Dustin, this calva command to eval, once you get used to it, you start using it so often, it’s so productive. Worth getting used to it. Here are the variants.

Dustin Getz18:10:24

@U0ETXRFEW i can't repro the 45350

Dustin Getz18:10:46

I used eval from start of toplevel form to cursor

pez18:10:49

I can’t reproduce it either. But I had been doing eval to cursor a lot of times before that, so maybe that is how to repro. (If the repro is any interesting, and simply not just a non supported use.)

Dustin Getz18:10:42

i just wanted to improve the tutorial

🙏 2
Vincent19:10:42

pez discovers electric, 楽しみ! (Looking forward to these discoveries)

metal 3
Dustin Getz17:10:53

We made a missionary quickstart, please try it and give feedback!

Dustin Getz18:10:01

Connection details for the missionary talk starting shortly: https://www.youtube.com/watch?v=ZcsTWFTmUO0

telekid19:10:46

sad I missed it, looking forward to watching the recording

telekid14:11:14

That link no longer works but this one does: https://www.youtube.com/watch?v=xtTCdT6e9-0

Vincent20:10:33

I added the ability for users to "upvote tags" that correspond to hyperlinks on http://NextApex.co but I still need to learn the tricks of the trade for catching the "upvote click" and not vacillating on it. There is some vacillation/wigglyness that occurs, I reckon due to the streaming nature of the differential. @dustingetz you mentioned there were some tricks, I will post the component code here although if you need more feel free to tell me

Vincent20:10:52

(e/defn TagItem [id]
  (e/server
    (let [e (xt/entity db id)
          xt-id   (:xt/id e)
          author (:tag/minted-by e)
          tag-id (:tag/id e)
          tag-minted-at (:tag/minted-at e)
          title (:tag/title e)
          target-id (:tag/target e)
          upvotes-set (:tag/upvotes-set e)
          upvotes (:tag/upvotes e)
          downvotes-set (:tag/downvotes-set e)
          downvotes (:tag/downvotes e)
          u (if (not= "" online-user) online-user nil)
          vw true]
      (e/client
        (dom/div (dom/props {:class "fr"})
          (dom/div (dom/props {:class "fc"}))
          (dom/div (dom/props {:class ["fc" "atag"]})
            (dom/div (dom/props {:class "upvote-tag"})
             (if (not (nil? u))
              (ui/button 
                (e/fn [] 
                  (e/server
                    (e/offload
                      #(xt/submit-tx !xtdb 
                                    [[:xtdb.api/put 
                                      (if (and u (contains? upvotes-set u) vw) ;;vw is verified login
                                        ;; user has upvoted, remove their upvote
                                        (-> e
                                            (update :tag/upvotes-set disj u)
                                            (update :tag/upvotes dec))
                                        ;; user hasn't upvoted, include their upvote
                                        (-> e
                                            (update :tag/upvotes-set conj u)
                                            (update :tag/upvotes inc)))]]))))
                (dom/props {:class (if (contains? upvotes-set u) "alreadyupvoted" "notyetupvoted")}) 
                (dom/text "▲ " (count upvotes-set)))
                (dom/div (dom/text "▲ " (count upvotes-set)))))
            (dom/div 
              (dom/props {:class ""}) 
              (dom/text title)))
          (when (= "R" online-user) 
            (dom/div (dom/props {:class "fc"})
              (ui/button 
              (e/fn [] 
                (e/server
                  (let [target-entity (xt/entity db target-id)
                        updated-target (update target-entity :item/tags disj title)]
                    (e/discard
                      (xt/submit-tx !xtdb [[:xtdb.api/put updated-target]
                                          [:xtdb.api/delete xt-id]]))))) 
                    (dom/props {:class "delete"})
                    (dom/text "✗")))))))))

Vincent20:10:50

#?(:clj
   (defn tags-for-newsitem [db newsitem-id]
     (->> (xt/q db '{:find [(pull ?t [:xt/id :tag/minted-by :tag/id :tag/minted-at :tag/title :tag/upvotes-set :tag/upvotes])]
                     :where [[?t :tag/target nws-id]]
                     :in [nws-id]} newsitem-id)
       (map first)
       (sort-by :tag/upvotes >)
       vec)))
The (sort-by :tag/upvotes >) sometimes makes the tags jump around to stay sorted. this makes the "vacillation" very apparent.