Giter Site home page Giter Site logo

djblue / portal Goto Github PK

View Code? Open in Web Editor NEW
867.0 18.0 81.0 6.39 MB

A clojure tool to navigate through your data.

Home Page: https://djblue.github.io/portal/

License: MIT License

Clojure 99.68% JavaScript 0.10% Emacs Lisp 0.15% Java 0.07%
clojure clojurescript rebl inspector datafy nav devtools babashka portal

portal's Introduction

portal

A clojure tool to navigate through your data.

cljdoc Clojars Project VS Code Extension Version Get help on Slack

The portal UI can be used to inspect values of various shapes and sizes. The UX will probably evolve over time and user feedback is welcome!

For an in-depth explanation of the UI, you can jump to the UI docs.

Demo

To get an overview of the Portal UI and workflow, checkout the following recording of a live demo I gave for London Clojurians.

London Clojurians Demo

More video presentations on Portal can be found here.

Usage

To start a repl with portal, run the clojure >= 1.10.0 cli with:

clj -Sdeps '{:deps {djblue/portal {:mvn/version "0.57.2"}}}'

or for a web clojurescript >= 1.10.773 repl, do:

clj -Sdeps '{:deps {djblue/portal {:mvn/version "0.57.2"}
                    org.clojure/clojurescript {:mvn/version "1.10.844"}}}' \
    -m cljs.main

or for a node clojurescript >= 1.10.773 repl, do:

clj -Sdeps '{:deps {djblue/portal {:mvn/version "0.57.2"}
                    org.clojure/clojurescript {:mvn/version "1.10.844"}}}' \
    -m cljs.main -re node

or for a babashka >=0.2.4 repl, do:

bb -Sdeps '{:deps {djblue/portal {:mvn/version "0.57.2"}}}'

or for a lein project.clj, add:

{:profiles {:dev {:dependencies [[djblue/portal "0.57.2"]]}}}

or as a global profile, add to ~/.lein/profiles.clj:

{:portal {:dependencies [[djblue/portal "0.57.2"]]}}

Note If you add Portal to a profile other than :dev, when starting a REPL start it with with-profiles +portal. The + is important.

or for Clojure CLR, checkout this example project,

or for examples on how to integrate portal into an existing project, look through the examples directory.

Note Portal can also be used without a runtime via the standalone version.

API

Try the portal api with the following commands:

;; for node and jvm
(require '[portal.api :as p])

;; for web
;; NOTE: you might need to enable popups for the portal ui to work in the
;; browser.
(require '[portal.web :as p])


(def p (p/open)) ; Open a new inspector

;; or with an extension installed, do:
(def p (p/open {:launcher :vs-code}))  ; jvm / node only
(def p (p/open {:launcher :intellij})) ; jvm / node only

(add-tap #'p/submit) ; Add portal as a tap> target

(tap> :hello) ; Start tapping out values

(p/clear) ; Clear all values

(tap> :world) ; Tap out more values

(prn @p) ; bring selected value back into repl

(remove-tap #'p/submit) ; Remove portal from tap> targetset

(p/close) ; Close the inspector when done

(p/docs) ; View docs locally via Portal - jvm / node only

Warning Portal will keep objects from being garbage collected until they are cleared from the UI.

Options

Options for portal.api/open:

Option Description Default Spec
:window-title Custom window title for UI "portal" string?
:theme Default theme for UI :portal.colors/nord
:value Root value of UI (atom (list))
:app Launch UI in Chrome app window true boolean?
:launcher Launch UI using this editor #{:vs-code :intellij :emacs}
:editor Enable editor commands, but use separate UI #{:vs-code :intellij :emacs}
:port Http server port for UI 0 int?
:host Http server host for UI "localhost" string?

For more documentation, take a look through the docs.

portal's People

Contributors

athos avatar brdloush avatar brianchevalier avatar burinc avatar coyotesqrl avatar cyrik avatar dakra avatar davidpham87 avatar dependabot[bot] avatar djblue avatar felipecortez avatar finalfantasia avatar handerpeder avatar holyjak avatar justone avatar lambeaux avatar lukaszkorecki avatar marloncorreia avatar mathisto avatar maxweber avatar mrnhrd avatar olymk2 avatar pez avatar pfeodrippe avatar rads avatar rfhayashi avatar rzwiefel avatar the-alchemist avatar walterl avatar wilkerlucio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

portal's Issues

Dies on objects

Portal dies on objects, it seems.

For example, after tapping something like,

{:name "sara" :email "[email protected]" :fn println}

the session is busted, and it seems to receive no further values until the JVM is rebooted.

different values rendering the same

We ran into the following example:

Calling this a few times

(-> [:portal.viewer/vega-lite 
     {:encoding
      {:y {:field "y", :type "quantitative"},
       :x {:field "x", :type "quantitative"}},
      :mark {:type "circle", :size 500},
      :data {:values
             (vec
              (for [i (range 9)]
                {:x i :y (rand)}))}}]
    (#(do (println %)
          %))
    (with-meta
      {:portal.viewer/default
       :portal.viewer/hiccup})
    portal.api/submit)

gives identical plots, while the printed values are different each time.

Quoting @djblue's explanations at Slack:

So I think this is the result of how cljs does hashing for floats

;; in cljs
(hash 0.0) ;; => 0
(hash 0.5) ;; => 0
(hash 1.0) ;; => 1
(hash 1.5) ;; => 1

https://stackoverflow.com/questions/45637233/clojurescript-floats-hashed-as-ints

If you submit a value in between both charts, it should work .

For now, something like:

(-> [:<>
     {:key (rand)}
     [:portal.viewer/vega-lite
      {:encoding
       {:y {:field "y", :type "quantitative"},
        :x {:field "x", :type "quantitative"}},
       :mark {:type "circle", :size 500},
       :data {:values
              (vec
               (for [i (range 9)]
                 {:x i :y (rand)}))}}]]
    (with-meta
      {:portal.viewer/default
       :portal.viewer/hiccup})
    portal.api/submit)

should fix it.

Issues on Firefox

Thanks for the great tool! I noticed some issues on Firefox, so I figured I'd open an issue to help track these.

  • Command Palette doesn't show any choices

You can use the command palette, by typing in what you want and hitting enter, but the list of options shows as empty.

  • Command Palette keyboard shortcut is unavailable

It's currently bound to Ctrl-Shift-p (on non-mac), which in FF opens a private browsing window. Seems it won't let you override that. As mentioned before in Slack my suggestion would be to use (perhaps in addition) ctrl-j, as used in Nextjournal.

Custom icon for Portal window

Hello,

it would be nice if the browser window, that gets spawned by Portal, had its own custom portal icon.

Currently Portal window receives generic browser icon (green Google Chrome icon in my case) and therefore it is quite hard to find it when switching between windows using alt-tab. Similarly, it's confusing to see portal windows being grouped with other browser windows in Plank dock (on linux) or similar dock.

Not sure if it's achievable by some chrome CLI options, or via some system-specific tools such as xseticon, xprops etc.

Just an idea to consider.

BTW portal is a great tool, you're doing really awesome work! 👏 👍

Ability to start Portal without UI

Am I able to start Portal without a UI?

For example, a p/open that does not open a window, it just starts the server (so I can link later somewhere using the new p/url function), returning the usual Portal object (p/start returns a map).

Generating nested data drill-down code based upon the current Portal selection

Now that Portal works with VSCode (and soon IntelliJ/Cursive), it may be time to explore some code generation features.

This is a new feature idea for Portal and I wanted to start crowdsourcing some thought on the matter. How would the community feel about adding a "Where am I?" feature to complement dereferencing the Portal atom. It would output the actual code that, when evaluated, outputs the data you have currently selected with respect to Portal's root of the data.

In the simplest case, it is generating code that "drills down" for you, in order to fetch a nested value. But it could evolve to do more.

Some initial thoughts:

  • The code being generated is meant for "drilling down" or "navigating" into nested data structures.
  • It's okay if there's minimal utility when dealing with data that's more flat than nested.
  • Reasonable default might be to drill with respect to Portal's root.
  • Alternative is to specify pre-drill code that executes prior to generating the drill code so you need not always start from root.
  • It should be possible to add alternative flavors of the generated code across collections, maps, reduces, etc. based on what the user is trying to do.
  • Could borrow some ideas from generative testing to ensure accuracy of generated code relative to the data loaded in Portal.

Some things that would help:

  • Has this been done before (links to projects or papers appreciated - I'm kind of stuck in the "I don't know what I don't know" loop when trying to search for this specifically)?
  • Alternative ideas for identifying the boundary points for drilling operations; more specifically, how to select a starting point beyond the Portal atom root.
  • Any other ideas regarding this capability or code generation problems in general.

Some early implementation notes describing potential approaches:

  • Establish a mapping of type → function, for reasonably appropriate functions, that drill deeper into that type.

No config file found: intellij.edn

Hello
Getting an error saying No config file found: intellij.edn
while trying to use intellij plugin

I'm using MacOS 12.5.1
And IntelliJ IDEA 2021.3.2 (Ultimate Edition)
Also I have [djblue/portal "0.30.0"] in my lein dependencies
I have a Portal Inspector plugin installed (0.30.0)

my code looks like this:

(ns my.core
  (:require
   [portal.api :as p]

(def p (p/open {:launcher :intellij}))

Here is a stacktrace

Syntax error macroexpanding at (core.clj:1:106).
No config file found: intellij.edn
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3719)
clojure.lang.ExceptionInfo: No config file found: intellij.edn {:options {:launcher :intellij}, :config-file "intellij.edn", :search-paths ("/Users/ts1503/Projects/dtower" "/Users/ts1503/Projects" "/Users/ts1503" "/Users" "/")}
	at portal.runtime.jvm.launcher$get_config.invokeStatic(launcher.clj:25)
	at portal.runtime.jvm.launcher$get_config.invoke(launcher.clj:14)
	at portal.runtime.jvm.launcher$remote_open.invokeStatic(launcher.clj:32)
	at portal.runtime.jvm.launcher$remote_open.invoke(launcher.clj:31)
	at portal.runtime.jvm.launcher$eval3843$fn__3844.invoke(launcher.clj:47)
	at clojure.lang.MultiFn.invoke(MultiFn.java:229)
	at portal.runtime.browser$open.invokeStatic(browser.cljc:113)
	at portal.runtime.browser$open.invoke(browser.cljc:106)
	at portal.runtime.jvm.launcher$open.invokeStatic(launcher.clj:73)
	at portal.runtime.jvm.launcher$open.invoke(launcher.clj:68)
	at portal.api$open.invokeStatic(api.cljc:64)
	at portal.api$open.invoke(api.cljc:54)
	at portal.api$open.invokeStatic(api.cljc:62)
	at portal.api$open.invoke(api.cljc:54)
	at clojure.lang.AFn.applyToHelper(AFn.java:154)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3714)
	at clojure.lang.Compiler$DefExpr.eval(Compiler.java:457)
	at clojure.lang.Compiler.eval(Compiler.java:7199)
	at clojure.lang.Compiler.eval(Compiler.java:7149)
	at clojure.core$eval.invokeStatic(core.clj:3215)
	at clojure.core$eval.invoke(core.clj:3211)
	at nrepl.middleware.interruptible_eval$evaluate$fn__968$fn__969.invoke(interruptible_eval.clj:87)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1990)
	at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1990)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at nrepl.middleware.interruptible_eval$evaluate$fn__968.invoke(interruptible_eval.clj:87)
	at clojure.main$repl$read_eval_print__9206$fn__9209.invoke(main.clj:437)
	at clojure.main$repl$read_eval_print__9206.invoke(main.clj:437)
	at clojure.main$repl$fn__9215.invoke(main.clj:458)
	at clojure.main$repl.invokeStatic(main.clj:458)
	at clojure.main$repl.doInvoke(main.clj:368)
	at clojure.lang.RestFn.invoke(RestFn.java:1523)
	at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:84)
	at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:56)
	at nrepl.middleware.interruptible_eval$interruptible_eval$fn__999$fn__1003.invoke(interruptible_eval.clj:152)
	at clojure.lang.AFn.run(AFn.java:22)
	at nrepl.middleware.session$session_exec$main_loop__1067$fn__1071.invoke(session.clj:202)
	at nrepl.middleware.session$session_exec$main_loop__1067.invoke(session.clj:201)
	at clojure.lang.AFn.run(AFn.java:22)
	at java.base/java.lang.Thread.run(Thread.java:833)

What I'm doing wrong?
Should I create intellij.edn manually?

Please help

Add support for brave-browser as chrome-bin

Hello,
I'm starting to use Portal and encountered a slight inconvenience, it does not recognize Brave browser
Brave is another chromium based browser which can probably be used just like the other executables found by get-chrome-bin, and supports launching in app mode.
The linux executable is called brave-browser, not sure regarding other operating systems.

Thanks

Should it work on windows?

I am using Windows 10, starting portal in the REPL with

clojure -Sdeps '{:deps {djblue/portal {:mvn/version """"""0.4.0""""""}}}'

I then follow the example from the webpage:

Clojure 1.10.1
user=> (require '[portal.api :as p])
nil
user=> (p/open)
nil
user=> (p/tap)
nil
user=> (tap> :hello)

A browser-tab is opened (on p/open) but nothing is ever displayed. The window stays blank...

Feature request: navigate multiple level at the same time

thanks for the great tool!

screenshot from hacker news demo
image
currently, if I click on the item id. it would just return the id as a value.

I want the user to be able to supply a nav function in meta similar to this

(defn nav-multiple [_coll k v]
    (if (= k [:submitted :nth])
      (let [item-id v]
        (nav-item item-id))
      v))

when the id is clicked, invoke nav-item. achieve the same effect as clicking on the submitted vector, then click on the id.

might be related to #77

portal.main failure with 0.5.0 and babashka 0.2.0

Hi. Thanks for this awesome tool. When I tried this with the latest portal and babashka, I get the following failure:

$ cat deps.edn | bb -cp `clj -Spath -Sdeps '{:deps {djblue/portal {:mvn/version "RELEASE"}}}'` -m portal.main edn
----- Error --------------------------------------------------------------------
Type:     java.lang.NullPointerException
Location: portal/http_socket_server.clj:81:21

----- Context ------------------------------------------------------------------
77:                             (try (.accept server-socket)
78:                                  (catch Exception _e))]
79:                    (start-worker-thread client-socket handler))))}))
80:
81: (defn wait [server] @(:future server))
                        ^---
82:
83: (defn stop [server]
84:   (.close ^ServerSocket (:server-socket server)))

----- Locals -------------------------------------------------------------------
server: nil

----- Stack trace --------------------------------------------------------------
clojure.core/deref             - <built-in>
portal.http-socket-server/wait - portal/http_socket_server.clj:81:21
portal.http-socket-server/wait - portal/http_socket_server.clj:81:1
portal.main                    - portal/main.clj:71:5
clojure.core/apply             - <built-in>
user                           - <expr>:1:36

I didn't know if this failure was known. Is this related to babashka/sci#401?

Any chance of a figwheel example ?

I have added the requirement to deps.edn, but i am not sure how to make the web app launch, the example uses -m "cljs.main" but in figwheel you don't normally do this.

In my dev.cljs.edn file I have this config which has a load of extra mains, I figure I need to add an entry point in there tried a few things, is this the right way or should I be launching it from the repl in the user.cljs namespace perhaps ?

^{:extra-main-files
  {:devcards {:main cards.core}
   :portal {:main portal.web}
   :testing {:main website.test-server}}
  :auto-testing true
  }
{:output-to "resources/public/cljs-out/dev-main.js"
 :closure-defines {website.state/environment "development"}
 :optimizations :none
 :pretty-print true
 :source-map true
 :source-map-timestamp true
 :devcards true
 :main website.core}

Provide context aware navigation.

This would be a feature enhancement currently focused on :portal.view/table such that when clicking on the index column, instead of navigating to the element which is somewhat pointless, will instead transition the view to column mode for that specific index.

Feature Request: Portal standalone with vscode goto definition

Currently launching portal with (p/open {:launcher :vs-code}) does nothing if there is no portal plugin, but if you call "go to definition" in the standalone launcher it tries to do that in emacs.
It would be great to have the launcher option separate from the IDE selection option.

If you want to I can write a PR for this once I find some time.

Feature Request: Shortcut for selecting the element in the portal list

Hello :-)

Thanks a lot again for the client API. I am starting to use portal in my workflow with emacs and portal is basicaly allows me to browse data from various projects.

May I just ask if it possible to focus the data panel with a shortcut? I am using the TAB key now to cycle/navigate, but it would be helpful to have a shortcut (much like CTRL-j).

Best regards,
David

PWA - searching for Preferences folder not working when using multiple chrome profiles

According to...

https://github.com/djblue/portal/blob/master/src/portal/runtime/jvm/launcher.clj#L44-L46

...portal is looking for ~/.config/google-chrome/Default/Preference file. But if you're using multiple profiles in your chrome, then it's likely that Default folder does not exist. Instead, you have ~/.config/google-chrome/Profile\ 1/Preferences, ~/.config/google-chrome/Profile\ 2/Preferences etc.

It might be better to either

  • look recurively for all Preferences files under ~/.config/google-chrome/
  • allow user to somehow override the folder location manually via some options map, system ENV property would be enough IMO

By the way it might be a good idea to write some PWA information in README.md and mention that:

  • you can visit djblue.github.io/portal and click "Install portal...`
  • thanks to that, portal will preferrably try to run the PWA instead of generic chrome window
    (I hope I got this right 😄 )

Provide api access to `remove-tap`

While it's trivial to remove the tap (or clear all open taps), it would be nice if the api provided a mechanism to do that. I'd think either a new fn, such as

(defn untap
  "Remove portal as a tap> target."
  []
  (remove-tap #'rt/update-value)
  nil)

or a side-effect of closing inspector windows like this

(defn close
  "Close all current inspector windows and remove taps."
  []
  (remove-tap #'rt/update-value)
  (l/close)
  nil)

would work best.

Headless serving mode

Hi, (this looks awesome!)

I would like to know if it would make sense to launch the portal web server in headless mode, delegating to the user the responsibility of opening it up in their browser themselves.

I'm asking because we're trying to use it from a Windows WSL 2 Ubuntu image. Those images don't have windowing capabilities, only terminal capabilities. If they could just spit up the served url and port, I think we'd be fine to use portal from our Windows host chrome.

Thanks for any answer!

Support vim keybindings

The user should be able to at least use h, j, k, l for navigation, and maybe easily customize their keybindings through a config file. If this is easily doable and wanted as a feature, I can give it a try.

Some numeric values do not display correctly in Portal

Portal is not able to accurately display numeric values that exceed what can be represented in Javascript. For instance, the long value 4611681620380904123 shows up in Portal as 4611681620380904000. This can be confusing when using Portal with a Clojure repl.

Publish Portal to Open VSX

Dear djblue,

Please publish this extension to the Open VSX marketplace.

Context

Unfortunately, as Microsoft prohibits usages of the Microsoft marketplace by any other products or redistribution of .vsix files from it, in order to use VS Code extensions in non-Microsoft products, we kindly ask that you take ownership of the VS Code extension namespace in Open VSX and publish this extension on Open VSX.

What is Open VSX? Why does it exist?

Open VSX is a vendor neutral alternative to the MS marketplace used by most other derivatives of VS Code like VSCodium, Gitpod, OpenVSCode, Theia-based IDEs, and so on.

You can read on about Open VSX at the Eclipse Foundation's Open VSX FAQ.

How can you publish to Open VSX?

The docs to publish an extension can be found here. This process is straightforward and shouldn't take too long. Essentially, you need an authentication token and to execute the ovsx publish command to publish your extension. There's also a doc explaining the whole process with an example GitHub Action workflow.

Feature Request: user defined callbacks on vega views

I'd love to be able to extend already defined views. I've been thinking that the easiest way to get most of the functionality would be by being able to pass in an optional map of functions that can be called back into the hosting runtime.

For me its mostly interesting on the Vega view, so playing around with it I came up with the following modification:

(defn vega-embed [opts value]
  (let [theme (theme/use-theme)
        doc (deep-merge (default-config theme) value {:title ""})
        portal-opts (:portal-opts value)
...
...
    (react/useEffect
     (fn []
       (when-let [view (.-current view)]
         (let [width (- width 2
                        (* 2 (:padding theme)))
               callback (fn [event item] 
                          (when-let [callback (:click-callback portal-opts)]
                            (when-let [datum (if (.hasOwnProperty item "datum") (.-datum item) nil)]
                              (state/invoke callback (js->clj datum)))))]
           (.width view width)
           (.height view (* width 0.8))
           (.addEventListener view "click" callback)
           (.run view))))
     #js [init (.-current view) width])

This would have to be cleaned up and extended, but it works if you register any :click-callback passed in function as a command.

Would you be interested in a pull request for a clean version of the feature?

Oh btw, my usecase would be in omni-trace to be able to callback into the code so that the flamegraph can be extended or functions can be rerun.

I'd have just defined my own view, but unless I'm mistaken its not currently possible to do so without forking the ui code.

VSCode Extension: allow for dragging the tab around

I'm not sure if this is a VSCode bug, but I realised that when I'm trying to drag the Portal tab around, the whole window is also being dragged with it. A very strange behaviour, as if the drag events are passed to both the tab, and the window itself.

To reproduce:

  • Make a left/right split in VSCode, open a few files in each side.
  • Open portal via the extension.openPortal command (it shows up always on the left side)
  • Try to drag any editor tab from the left side.

Expected behaviour:

  • The editor tabs can be rearranged

Actual behaviour:

  • The whole window is moved

The behaviour persists even if the Portal tab is closed, until a window reload.
The right side split is unaffected.

Shortcut for search

Hi @djblue,
Would it be possible to provide a shortcut for focusing on the search/filter input? Perhaps '/'? I could give this a shot sometime soon if you'd like. Could also be useful to mention the shortcuts available in

(def ^:private keymap
from the readme.
Thanks again for the awesome tool! Been using it at work. Cheers

Bug dev: dev-cljs aliases not defined

Hello,

I am trying to add a new viewer to portal (adding plotly charts), and as I am using emacs, it occurred to me that dev-cljs was not defined in deps.edn.

Best regards,
David

YAML support

With the ubiquity of YAML format, it would be useful to have a direct support for it from the cli.

I have started an experiment on a fork, which seems to work fine, but it could use some further development.

After upgrade to 0.8.0 p/close causes timeout error on shutdown hook

(.addShutdownHook
    (Runtime/getRuntime)
    (Thread. #(p/close)))

Stacktrace

Press CTRL+C to exit

^C^CException in thread "Thread-1" clojure.lang.ExceptionInfo: Portal request timeout {:type :sci/error, :line 46, :column 11, :message {:op :portal.rpc/close, :portal.rpc/id 2}, :callstack #object[clojure.lang.Delay 0x3ba0d751 {:status :pending, :val nil}], :file "portal/runtime/jvm/client.clj", :locals {session-id #uuid "be88a78a-47cd-4ba6-a43c-264c36c77adf", message {:op :portal.rpc/close, :portal.rpc/id 2}, temp__8814__auto__ #object[sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887 0x4b1e5a16 "sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887@4b1e5a16"], send! #object[sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887 0x4b1e5a16 "sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887@4b1e5a16"], id 2, response :portal.runtime.jvm.client/timeout}, :session-id #uuid "be88a78a-47cd-4ba6-a43c-264c36c77adf"}
	at sci.impl.utils$rethrow_with_location_of_node.invokeStatic(utils.cljc:106)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:617)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_if.invokeStatic(interpreter.cljc:100)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_if.invokeStatic(interpreter.cljc:99)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.fns$parse_fn_args_PLUS_body$fn__12883.invoke(fns.cljc:29)
	at sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887.doInvoke(fns.cljc:53)
	at clojure.lang.RestFn.invoke(RestFn.java:421)
	at sci.impl.vars.SciVar.invoke(vars.cljc:317)
	at sci.impl.interpreter$fn_call.invokeStatic(interpreter.cljc:567)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:617)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_do_STAR_.invokeStatic(interpreter.cljc:521)
	at sci.impl.interpreter$eval_do.invokeStatic(interpreter.cljc:530)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_if.invokeStatic(interpreter.cljc:100)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_do_STAR_.invokeStatic(interpreter.cljc:521)
	at sci.impl.interpreter$eval_do.invokeStatic(interpreter.cljc:530)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_if.invokeStatic(interpreter.cljc:99)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_if.invokeStatic(interpreter.cljc:100)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:601)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.fns$parse_fn_args_PLUS_body$fn__12883.invoke(fns.cljc:29)
	at sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887.doInvoke(fns.cljc:53)
	at clojure.lang.RestFn.invoke(RestFn.java:457)
	at sci.impl.interpreter$fn_call.invokeStatic(interpreter.cljc:567)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:617)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_let.invokeStatic(interpreter.cljc:85)
	at sci.impl.interpreter$eval_let.doInvoke(interpreter.cljc:61)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:570)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_do_STAR_.invokeStatic(interpreter.cljc:521)
	at sci.impl.interpreter$eval_do_STAR_.invoke(interpreter.cljc:518)
	at sci.impl.fns$parse_fn_args_PLUS_body$fn__12885.invoke(fns.cljc:30)
	at sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887.doInvoke(fns.cljc:53)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at sci.impl.vars.SciVar.invoke(vars.cljc:313)
	at sci.impl.interpreter$fn_call.invokeStatic(interpreter.cljc:567)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:617)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_do_STAR_.invokeStatic(interpreter.cljc:521)
	at sci.impl.interpreter$eval_do_STAR_.invoke(interpreter.cljc:518)
	at sci.impl.fns$parse_fn_args_PLUS_body$fn__12885.invoke(fns.cljc:30)
	at sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887.doInvoke(fns.cljc:53)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at sci.impl.vars.SciVar.invoke(vars.cljc:313)
	at sci.impl.interpreter$fn_call.invokeStatic(interpreter.cljc:567)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:617)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.fns$parse_fn_args_PLUS_body$fn__12883.invoke(fns.cljc:29)
	at sci.impl.fns$parse_fn_args_PLUS_body$run_fn__12887.doInvoke(fns.cljc:53)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at clojure.lang.AFn.run(AFn.java:22)
	at java.lang.Thread.run(Thread.java:834)
	at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:519)
	at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
Caused by: clojure.lang.ExceptionInfo: Portal request timeout {:session-id #uuid "be88a78a-47cd-4ba6-a43c-264c36c77adf", :message {:op :portal.rpc/close, :portal.rpc/id 2}}
	at sci.impl.vars.SciVar.invoke(vars.cljc:317)
	at sci.impl.interpreter$fn_call.invokeStatic(interpreter.cljc:567)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:617)
	at sci.impl.interpreter$interpret.invokeStatic(interpreter.cljc:651)
	at sci.impl.interpreter$interpret.invoke(interpreter.cljc:633)
	at sci.impl.interpreter$eval_throw.invokeStatic(interpreter.cljc:341)
	at sci.impl.interpreter$eval_special_call.invokeStatic(interpreter.cljc:581)
	at sci.impl.interpreter$eval_call.invokeStatic(interpreter.cljc:610)```

Shortcut for `datafy`

Hi,

Would it be possible to create a shortcut for datafy (e.g. SHIFT + ENTER)? Maybe it was discussed before, but I didn't find anywhere.

Thanks

Allow sorted-map to be displayed on it's original order

Portal tries to sort any map on it's keys, even sorted-maps that might have a different ordering (using custom comparator). Ideally, sorted-maps would be printed on their original order instead of trying to sort them.

websocket connection doesn't use correct port

I use something like

(do
 ((requiring-resolve 'portal.api/open)  {:portal.launcher/port 1111 :portal.launcher/host "strange.home.arpa"})
 (add-tap (requiring-resolve 'portal.api/submit)))

to start portal and then click on the link it prints out like

Goto http://strange.home.arpa:1111?81444db3-34f5-4a4a-aebd-821bae6bfe7a to view portal ui.

which results in a blank page and a console log with

Firefox can’t establish a connection to the server at ws://strange.home.arpa/rpc?81444db3-34f5-4a4a-aebd-821bae6bfe7a.

in it in my browser

Feature request: Standalone/Server mode

Hello,

Thanks a lot, portal is a great addition to the Clojure ecosystem.

I wonder if that was possible to create a standalone server mode, and clients could connect to it by sending request to the server. In my mind , you could start a server portal with babashka in a a given port (say 1664), then any client (clj/CLJS) could send edn data to the server through http request. Optimally, a tap register function would be provided so that user just have to provide the port of the server.

This would disentangle portal from the client process and ease the integration with other tools (such as emacs) and shadow-CLJS/hot reloading) and ithe workflow would then resemble to the nrepl/socket repl.

An example of such implementation is the shadow-CLJS inspect server.

Best regards,
David

Unable to resolve using (add-tap #'p/submit)

I am connection to an nrepl on a server with lein repl :connect 7679and I get the following exception thrown when (add-tap #'p/submit) but all works when I use the depreciated (p/tap)

user=> (require '[portal.api :as p])
nil
user=> (add-tap #'p/submit)
             java.lang.RuntimeException: Unable to resolve var: p/submit in this context
clojure.lang.Compiler$CompilerException: Syntax error compiling var at (1:1).

user=> (p/tap)
nil
user=>

This only happens when I connect to a running nrepl.

Cheers

Multiple selection not working in Manjaro

I'm trying to select multiple values by holding ALT and clicking on them, the result is that it just selects the last one I clicked.

This is my system information:

$ uname -a
=> Linux nmkip 5.10.79-1-MANJARO #1 SMP PREEMPT Fri Nov 12 20:26:09 UTC 2021 x86_64 GNU/Linux

This is what is being returned by window.navigator.platform

window.navigator.platform
=> 'Linux x86_64'

vs-code extension not working in "remote" connection

I use Calva in a "remote-connection".
The portal-vs-code-extension windows opens for me, after rnning:

(def p (p/open {:launcher :vs-code})) 

but is completely empty, and does not render anything
No error message seen.

Is it supposed to work ?

When using IntelliJ extension, enable jump-to-code in `:portal.viewer/stack-trace` view

(I'm sure this could be implemented for VSCode as well; that would be a separate ticket, I think.)

When working on...let's call it linguine code so as not to be too crude...I find I often write taps like the following:

(tap> {:data1 d1 :data2 d2 :whence (ex-info "whence" {})})

so I can walk back through the callstack. It's all there, and I can manually move around in the editor to the ns and line I need, but it would be nice if it the integrated Portal window could automatically jump when I click on a line in the stack trace view.

I know that it would likely use the com.intellij.util.PsiNavigateUtil.navigate method, but I don't know how to attach that UI action in the plugin.

StackOverflowError when submitting a huge datastructure with parsed xml

(In the JVM) I was trying to inspect a datastructure with a huge XML parsed with clojure.data.xml in it.

(def huge ,,,)
=> #'cs-load-test.request-gen/huge

(p/open)
=> {:session-id #uuid"15233ae2-3283-42b1-9c37-e0ad6d215e8f"}

(p/submit huge)
Execution error (StackOverflowError) at portal.runtime.cson/tagged-list (cson.cljc:135).
null

(pst)
StackOverflowError 
	clojure.lang.LazySeq.sval (LazySeq.java:42)
	clojure.lang.LazySeq.seq (LazySeq.java:51)
	clojure.lang.RT.seq (RT.java:535)
	clojure.core/seq--5420 (core.clj:139)
	clojure.core/concat/cat--5513/fn--5514 (core.clj:736)
	clojure.lang.LazySeq.sval (LazySeq.java:42)
	clojure.lang.LazySeq.seq (LazySeq.java:51)
	clojure.lang.RT.seq (RT.java:535)
	clojure.core/seq--5420 (core.clj:139)
	clojure.core.protocols/seq-reduce (protocols.clj:24)
	clojure.core.protocols/fn--8170 (protocols.clj:75)
	clojure.core.protocols/fn--8170 (protocols.clj:75)
=> nil

Not sure the depth should matter (or how to get it correctly), but

(defn get-depth [x]
  (if (seqable? x)
    (inc (reduce max 1 (map get-depth x)))
    1))


(get-depth huge)
=> 851

Windows VS Code extension fails to display

The VS Code integration does not seem to fire-up on Windows. It appears to be a problem with making the directory ~/.portal, probably an issue with an errant leading /.


Uncaught Errors (1)
ENOENT: no such file or directory, mkdir '/C:/Users/ABC123/.portal'

Incompatible with http-kit protocols?

When I create a user.clj like this:

(ns user
  (:require [portal.api :as p]))

(defn portal []
  (p/open)
  (add-tap #'p/submit))

and load it into an nREPL, I get:

Syntax error (IllegalArgumentException) compiling http/server-stop! at (portal/runtime/jvm/launcher.clj:68:3). No single method: server_stop_BANG_ of interface: org.httpkit.server.IHttpServer found for function: server-stop! of protocol: IHttpServer

Unable to load VSCode Extension

I'm on the latest macOS Ventura 13.0.1 &. VSCode 1.73.1

Tried install, disable & enable the extension but always got the following error. Any clue?

Screenshot 2022-12-01 at 16 07 38

Vega-lite viewer cuts off right hand edge of chart

When viewing a vega-lite chart, it looks like the vega-lite view extends past the right hand edge of the visible component. The red highlighting around the selected portal item is missing on the right hand edge of the vega-lite view. This leads to some data points not getting displayed.

This is with 0.19.2 running from clojure on a mac.

Multi-select doesn't work on Ubuntu (on the portal-talk repo)

Tried using alt and a bunch of other key combos and nothing worked to be able to multi-select. :(

Using a basic Dell Keyboard.

I actually cloned this repo onto my machine and tried with the dev build, and there, multi-select did work.
However on the portal-talk repo it doesn't. Really unclear why. I added a keyboard event listener onto the chrome window running portal and it properly captures the alt key being pressed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.