diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js
index 72ead3a9db..d35dbb164b 100644
--- a/frontend/components/Editor.js
+++ b/frontend/components/Editor.js
@@ -678,7 +678,7 @@ export class Editor extends Component {
allow_other_selected_cells ? this.state.selected_cells : [cell_id],
get_avaible_versions: async ({ package_name, notebook_id }) => {
const { message } = await this.client.send("nbpkg_available_versions", { package_name: package_name }, { notebook_id: notebook_id })
- return message.versions
+ return message
},
}
this.actions = { ...this.real_actions }
diff --git a/frontend/components/PkgStatusMark.js b/frontend/components/PkgStatusMark.js
index fd2eae561d..ce1d4c68bc 100644
--- a/frontend/components/PkgStatusMark.js
+++ b/frontend/components/PkgStatusMark.js
@@ -1,6 +1,7 @@
import { open_pluto_popup } from "../common/open_pluto_popup.js"
import _ from "../imports/lodash.js"
import { html, useEffect, useState } from "../imports/Preact.js"
+import { open_icon } from "./Popup.js"
export const nbpkg_fingerprint = (nbpkg) => (nbpkg == null ? [null] : Object.entries(nbpkg).flat())
@@ -23,6 +24,7 @@ const can_update = (installed, available) => {
* @property {string} hint_raw
* @property {string[]?} available_versions
* @property {string?} chosen_version
+ * @property {string?} package_url
* @property {boolean} busy
* @property {boolean} offer_update
*/
@@ -30,21 +32,27 @@ const can_update = (installed, available) => {
/**
* @param {{
* package_name: string,
+ * package_url?: string,
* is_disable_pkg: boolean,
- * available_versions: string[]?,
+ * available_versions?: string[],
* nbpkg: import("./Editor.js").NotebookPkgData?,
* }} props
* @returns {PackageStatus}
*/
-export const package_status = ({ nbpkg, package_name, available_versions, is_disable_pkg }) => {
+export const package_status = ({ nbpkg, package_name, available_versions, is_disable_pkg, package_url }) => {
let status = "error"
let hint_raw = "error"
let hint = html`error`
let offer_update = false
+
+ package_url = package_url ?? `https://juliahub.com/ui/Packages/General/${package_name}`
+
const chosen_version = nbpkg?.installed_versions[package_name] ?? null
const nbpkg_waiting_for_permission = nbpkg?.waiting_for_permission ?? false
const busy = !nbpkg_waiting_for_permission && ((nbpkg?.busy_packages ?? []).includes(package_name) || !(nbpkg?.instantiated ?? true))
+ const package_name_pretty = html`${package_name} `
+
if (is_disable_pkg) {
const f_name = package_name
status = "disable_pkg"
@@ -54,22 +62,25 @@ export const package_status = ({ nbpkg, package_name, available_versions, is_dis
if (chosen_version == null || chosen_version === "stdlib") {
status = "installed"
hint_raw = `${package_name} is part of Julia's pre-installed 'standard library'.`
- hint = html`${package_name} is part of Julia's pre-installed standard library.`
+ hint = html`${package_name_pretty} is part of Julia's pre-installed standard library.`
} else {
if (nbpkg_waiting_for_permission) {
status = "will_be_installed"
hint_raw = `${package_name} (v${_.last(available_versions)}) will be installed when you run this notebook.`
- hint = html`${package_name} v${_.last(available_versions)}
+ hint = html`${package_name_pretty} v${_.last(available_versions)}
will be installed when you run this notebook.`
} else if (busy) {
status = "busy"
hint_raw = `${package_name} (v${chosen_version}) is installing...`
- hint = html`${package_name} v${chosen_version}
+ hint = html`${package_name_pretty} v${chosen_version}
is installing...`
} else {
status = "installed"
hint_raw = `${package_name} (v${chosen_version}) is installed in the notebook.`
- hint = html`${package_name} v${chosen_version}
+ hint = html`
+ ${package_name_pretty}
+ v${chosen_version}
+
is installed in the notebook.`
offer_update = can_update(chosen_version, available_versions)
}
@@ -84,13 +95,13 @@ export const package_status = ({ nbpkg, package_name, available_versions, is_dis
} else {
status = "will_be_installed"
hint_raw = `${package_name} (v${_.last(available_versions)}) will be installed in the notebook when you run this cell.`
- hint = html`${package_name} v${_.last(available_versions)}
+ hint = html`${package_name_pretty} v${_.last(available_versions)}
will be installed in the notebook when you run this cell.`
}
}
}
- return { status, hint, hint_raw, available_versions, chosen_version, busy, offer_update }
+ return { status, hint, hint_raw, available_versions: available_versions ?? null, chosen_version, busy, offer_update, package_url }
}
/**
@@ -103,20 +114,20 @@ export const package_status = ({ nbpkg, package_name, available_versions, is_dis
* }} props
*/
export const PkgStatusMark = ({ package_name, pluto_actions, notebook_id, nbpkg }) => {
- const [available_versions, set_available_versions] = useState(/** @type {string[]?} */ (null))
+ const [available_versions_msg, set_available_versions_msg] = useState(/** @type {{ versions?: string[], package_url?: string }?} */ (null))
+ const [package_url, set_package_url] = useState(/** @type {string[]?} */ (null))
useEffect(() => {
let available_version_promise = pluto_actions.get_avaible_versions({ package_name, notebook_id }) ?? Promise.resolve([])
- available_version_promise.then((available_versions) => {
- set_available_versions(available_versions)
- })
+ available_version_promise.then(set_available_versions_msg)
}, [package_name])
const { status, hint_raw } = package_status({
nbpkg: nbpkg,
package_name: package_name,
is_disable_pkg: false,
- available_versions,
+ available_versions: available_versions_msg?.versions,
+ package_url: available_versions_msg?.package_url,
})
return html`
@@ -154,7 +165,6 @@ export const PkgActivateMark = ({ package_name }) => {
nbpkg: null,
package_name: package_name,
is_disable_pkg: true,
- available_versions: null,
})
return html`
diff --git a/frontend/components/Popup.js b/frontend/components/Popup.js
index 6b56502f60..2c48b47ad5 100644
--- a/frontend/components/Popup.js
+++ b/frontend/components/Popup.js
@@ -15,6 +15,7 @@ import { useEventListener } from "../common/useEventListener.js"
export const arrow_up_circle_icon = new URL("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/arrow-up-circle-outline.svg", import.meta.url)
export const document_text_icon = new URL("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/document-text-outline.svg", import.meta.url)
export const help_circle_icon = new URL("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/help-circle-outline.svg", import.meta.url)
+export const open_icon = new URL("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/open-outline.svg", import.meta.url)
/**
* @typedef PkgPopupDetails
@@ -180,7 +181,8 @@ const PkgPopup = ({ notebook, recent_event, clear_recent_event, disable_input })
set_pkg_status(null)
} else if (recent_event?.type === "nbpkg") {
;(pluto_actions.get_avaible_versions({ package_name: recent_event.package_name, notebook_id: notebook.notebook_id }) ?? Promise.resolve([])).then(
- (versions) => {
+ ({ versions, url }) => {
+ console.log({ url })
if (still_valid) {
set_pkg_status(
package_status({
@@ -188,6 +190,7 @@ const PkgPopup = ({ notebook, recent_event, clear_recent_event, disable_input })
package_name: recent_event.package_name,
is_disable_pkg: recent_event.is_disable_pkg,
available_versions: versions,
+ package_url: url,
})
)
}
diff --git a/frontend/editor.css b/frontend/editor.css
index 85567be5ef..67d1b4186c 100644
--- a/frontend/editor.css
+++ b/frontend/editor.css
@@ -2047,6 +2047,14 @@ pkg-popup .pkg-buttons {
flex-direction: row;
}
+.ionicon {
+ filter: var(--image-filters);
+}
+
+.package-name .ionicon {
+ margin-bottom: -0.1ch;
+}
+
a.stdout-info img,
pkg-popup .pkg-buttons img {
filter: var(--image-filters);
diff --git a/src/packages/PkgCompat.jl b/src/packages/PkgCompat.jl
index be75575159..c5627b0b35 100644
--- a/src/packages/PkgCompat.jl
+++ b/src/packages/PkgCompat.jl
@@ -377,6 +377,27 @@ function package_versions(package_name::AbstractString)::Vector
end
end
+function package_url(package_name::AbstractString)::Union{String,Nothing}
+ if is_stdlib(package_name)
+ "https://docs.julialang.org/en/v1/stdlib/$(package_name)/"
+ else
+ try
+ for reg in _parsed_registries[]
+ uuids_with_name = RegistryInstances.uuids_from_name(reg, package_name)
+ for u in uuids_with_name
+ pkg = get(reg, u, nothing)
+ if pkg !== nothing
+ info = RegistryInstances.registry_info(pkg)
+ return info.repo
+ end
+ end
+ end
+ catch e
+ @warn "Pkg compat: failed to get installable versions." exception=(e,catch_backtrace())
+ end
+ end
+end
+
# ⚠️ Internal API with fallback
"Does a package with this name exist in one of the installed registries?"
package_exists(package_name::AbstractString)::Bool =
diff --git a/src/webserver/Dynamic.jl b/src/webserver/Dynamic.jl
index 32b28f783b..5960c0ff74 100644
--- a/src/webserver/Dynamic.jl
+++ b/src/webserver/Dynamic.jl
@@ -557,8 +557,10 @@ end
responses[:nbpkg_available_versions] = function response_nbpkg_available_versions(🙋::ClientRequest)
# require_notebook(🙋)
all_versions = PkgCompat.package_versions(🙋.body["package_name"])
+ url = PkgCompat.package_url(🙋.body["package_name"])
putclientupdates!(🙋.session, 🙋.initiator, UpdateMessage(:🍕, Dict(
:versions => string.(all_versions),
+ :url => url,
), nothing, nothing, 🙋.initiator))
end
diff --git a/test/packages/PkgCompat.jl b/test/packages/PkgCompat.jl
index c30efc27bd..fdc3a604ed 100644
--- a/test/packages/PkgCompat.jl
+++ b/test/packages/PkgCompat.jl
@@ -32,6 +32,12 @@ import Pkg
end
+ @testset "URL" begin
+ @test PkgCompat.package_url("HTTP") == "https://github.com/JuliaWeb/HTTP.jl.git"
+ @test PkgCompat.package_url("HefefTTP") === nothing
+ @test PkgCompat.package_url("Downloads") == "https://docs.julialang.org/en/v1/stdlib/Downloads/"
+ end
+
@testset "Registry queries" begin
Pkg.Registry.add(pluto_test_registry_spec)
PkgCompat.refresh_registry_cache()