Fork me on GitHub
Lukas Domagala18:11:41

@djblue i’m thinking of investing some time into portal views and making it possible to get at least a simple new view loaded from the outside. would you be interested in a pr in that direction?


one simple option is to use hiccup to make custom views, I'm doing some of that, not as powerful as full control, but can go a long way

Lukas Domagala18:11:45

@U066U8JQJ my problem is that I want the view to have new interactions, which is not possible with the hiccup view. the only way to currently get any extra mouse interaction would be an iframe, but then i’ll need to start my own http server and reimplement parts of the communication layer of portal. we can already trigger generic user code through commands, we just need some way to hook view interactions into those commands, but I don’t see a generic way to do it without allowing full views to be loaded at runtime. although for my use-case i’d be happy with a more flexible vega view, but i can understand why would overcomplicate it for other people.


@U066U8JQJ do you have an example you can share?


@UJCC6CE9E sure, something like:

(tap> ^{:portal.viewer/default :portal.viewer/hiccup}
   [:h1 "Hello Custom Stuff"]
   [:input {:type "text" :placeholder "type here"}]])

thanks3 1

@U02EMBDU2JU agreed, for interactive stuff its harder


@U02EMBDU2JU, I'm curious what direction you are heading in. I've been playing with a few ideas recently. They essentially revolve around allowing user cljs code to be run in the client runtime and exposing an api to register custom viewers. In terms of running client code, I think sci would be the easiest direction, although I think bootstrap cljs could also work. Another complexity that I've ran into is allowing users to load js from npm, but I'm going to ignore that for now 😆 At the end of the day, I think the api should look something like (portal.api/eval-str "(js/alert 1)") .


So, for an extension example, you could load the extension in the host runtime via:

(portal.api/eval-str "(require 'my.extension)")
And my extension could looks like:
(ns my.extension
  (:require [portal.ui.api :as p])

(defn my-viewer [value]
  [:div {:on-click (fn [] ...)} ...])

(p/register-viewer! { :component my-viewer })


This api would also allow for setting up a custom repl 👌

Lukas Domagala20:11:07

@djblue yeah, I agree with you. I would have started with something like: registerViewer("{jobject creation} " ) That would be the most basic integration just to see how it pans out. Then I'd try to push a compiled cljs js file in there. Do you have your experiments somewhere public? Getting Sci to work would help for more casual use, you're right.


Nothing public yet, still needs a little clean up. Will let you know when I get something up.

Lukas Domagala21:11:11

@djblue I guess I'll wait for that then, kind of doesn't make sense if we both build the same thing. If you want some help I'm game

👍 1
Lukas Domagala11:11:47

@djblue btw have you thought about using selfhosted cljs for the ui? i haven’t looked into it at all, but the main reason we would want to avoid it is js download size, which is not really any issue for portal. it might just give us custom cljs views for “free”


I've also tried selfhosted cljs and that seems to work too. Not sure exactly which to pick yet, but either way it will be an implementation detail that users should not care about.


I think would be nice to try SCI first, its much more lightweight than selfhosted and gives you more control

👍 1

My other question is how would you expect to do development? Would a REPL be enough?

Lukas Domagala22:11:51

Good question, I haven't done any sci stuff yet. I was hoping I could ignore that it's sci and just write it inside the portal repo as a normal view, then copy it over to my own ns after I got it working.


That's a very interesting idea


I have a very similar question for @seancorfield! I'm working on a guide for some of my coworkers who are newer to clojure on installation/configuration/usage of clover/portal and was wondering if you'd be open to a PR that either fleshes out the readme or adds a separate file to serve that purpose


A documentation PR would be awesome! In terms of organization, I'm open to either. I've kept things in a single file for now because it makes it easier for users to find things, but at some point things do have to be broken out.


Sweet! I was primarily referring to this repo of Sean's, but a less opinionated guide may be helpful as well


Ohh, misunderstood. My bad :thumbsup:


All good! If I can easily flesh out some of the portal documentation while I'm at it I may as well

❤️ 1

@U24FM0Y3U Most folks using VS Code are going to want to use Calva for the REPL and will be using nREPL -- although the big plus of Clover is the ability to add all those custom commands rather than just some middleware that tap>s all evaluations.

💯 1

Of course I am biased in favor of using a Socket REPL instead of CIDER/nREPL for other reasons: if you use a Socket REPL for your editor, you can interact with any Clojure process -- local or remote -- easily by specifying the Socket REPL JVM options at startup...


Not to highjack this thread, but I feel like now with clojure-lsp and all the data visualization tools, clojure repls don't need to offer as much functionality, just eval is good enough. I've been playing with using a plain socket repl recently and haven't missed much, and it's much easier to customize!


True, and I may end up finding the time to write up a full step-by-step guide for calva as well, but as long as clover offers a good enough autocomplete/jump-to, it'll be enough for most people


The fact that it's light, fast, and minimal is a plus, but I also really like your hotkey cheat-sheet and wanted to build on that 🙂


@U24FM0Y3U Feel free to hit me up via DM if you have any Qs about any part of it. There's some Portal-specific stuff in my dot-clojure repo too (in dev.clj).


Oh perfect thank you! Yeah I'll be finishing this up over the course of this week as I have time

Lukas Domagala10:11:49

> Most folks using VS Code are going to want to use Calva for the REPL and will be using nREPL -- although the big plus of Clover is the ability to add all those custom commands rather than just some middleware that `tap>`s all evaluations. @seancorfield if you have a minute: how does clover accomplish the custom command thing? I wanted something like that in calva for some time, but wasn’t sure where to start


@U02EMBDU2JU It uses sci to run a config.cljs file in the context of its own code (so you have access to an editor API).


You've seen my config? That adds "tasks" that can be run per the key bindings in that repo.


As I recall, the downside is that these tasks do not show up in the command palette (but I only ever use them via hot keys so it doesn't matter to me).

Lukas Domagala18:11:30

@seancorfield thanks for the info, getting that into calva would be nice, but i doubt they’d wanna have a sci dependency. i’ll ask though and try to get it in myself if possible.


Repost as recommended in #calva Has anyone gotten the portal vscode plugin working with calva? I’ve got a repl started, but when I run portal/open nothing shows up

R.A. Porter21:11:15

I don't use Calva, so the extent of my input is to ask if you're passing {:launcher :vs-code} to the call to open.


From what repl do you run that? Or does it not matter?


I’m trying to isolate variables, I ran that same thing with calva’s integrated repl connected to a repl server running in a docker container

R.A. Porter22:11:18

See...I'm already useless to you. 😄 @djblue will no doubt be around shortly.


@U01EB0V3H39 I suspect the problem there is the Docker container not having ports open so that VS Code's Portal extension can communicate with the little web server that Portal starts in the JVM...


Why are you using a Docker container for development?


I can understand using Docker to manage services your code might need -- databases, search engines, etc -- but I can't understand why anyone would run their REPL inside a container like that, instead of running it locally on their machine.


It’s a long story, but I’ll try to tell it in 2 words: “microservices” and “environment standardization” 🤪


Yeah I can see why that’d be the problem. Thanks for the help!


You can call portal.api/open with a :portal.launcher/port parameter and ensure that port is available on the host via a port mapping, that should solve the ability to launch the UI in vs-code. The next problem is exposing the host to the container, which might involve setting the :host in the .portal/vs-code.edn .


Did you ever solve this, @U01EB0V3H39?


@djblue not sure how to config the :host . My symptoms is this error message when I launch portal:

Execution error (ConnectException) at  (
Connection refused


I did not. 1) the company abandoned that dev env approach, 2) I put Portal back on the shelf to check out later, and 3) since then I don’t work there anymore laughcry Good luck


@U0ETXRFEW is your setup similar to the one described above? Clojure repl process running in docker with vscode running on the host?


I hope you've picked Portal back down from that shelf, @U01EB0V3H39!


Well, "yay!" on 1 I suppose...


@djblue the setup above is a bit unclear, but yes, Clojure running in docker, VS Code on the host. I could run VS Code on the host as well, but there are also users with less cool editors.


> I hope you’ve picked Portal back down from that shelf, @U01EB0V3H39! It’s on my list…I’m sure I’ll get around to it eventually </famous-last-words>


@djblue, I expose the port from vs-code.edn from the container. But that alone did not fix it.


The Portal extension reads that EDN file locally to figure out the host/port to connect to - so you could create it manually on the "host" filesystem to point to the Docker container.


Or I guess you could cross mount the .Portal folder from host to Docker?


(typing on my phone from vacation in Hawaii so excuse the lack of formatting and any typos 😁)


I suspect the issue is the clojure process can't send the request to the vs-code instance since the vs-code extension is running on the host machine.


Something like --network="host" might fix it or manually updating the vs-code.edn to point to an alias for the host machine's localhost, something like {:host "host.docker.internal"}


.portal is mounted from the host.


Where would I put --network="host"?


The docker run command I think


Using "host.docker.internal" the portal window opens and the error message is gone. But the portal window is blank, so no party yet. 😃


I think now it's the inverse problem the host machine is trying to hit localhost to load the ui from the server that is in the docker container


To make it easy, you can hard code the port portal uses and make sure that port is forwarded to the host machine via the -p flag


docker run -d -p 1234:1234
(portal.api/start {:port 1234})


If we get this working, I'll probably put together a guide 👌


One thing to note is that if the server is already started, start won't do anything


I think I am doing the forwarding already. (Via my docker-compose config.) When I run everything locally I have had a port configured in vscode.edn and launched portal using: (portal.setup/init! {:launcher :vs-code}). Now trying with portal.api/start instead. It disregards the port option:

(portal.api/start {:port 63257})
=> {:http-server #object[org.httpkit.server.HttpServer 0x521f01f4 "org.httpkit.server.HttpServer@521f01f4"],
    :port 34643,
    :host "localhost"}


You might have to shutdown the server with a portal.api/close first if the server is already running and you want to start it with a different port


This was from a clean start of the REPL.


However, maybe not as clean as I first thought... Maybe the nrepl middleware starts something? After a close it started on the port I specified. And then launching gives me a working portal window (!!!)

awesome 4

You think it could be the middleware that is messing things up?


Now my start function looks like so.

(defn start-portal! [port]
  (portal.api/start {:port port})
  (portal.setup/init! {:launcher :vs-code}))
Works, but looks funny. 😃


I forgot you were also setting up shadow, or at least I assume so :thinking_face:


I could update the hook to also take a port 👌


That would be awesome. Yes, shadow is in my mix. 😃


Thanks! ❤️