From b9153a3efb710f696a71cb1db4858e5e8c051129 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Fri, 11 Oct 2024 09:09:45 +0200 Subject: [PATCH 1/2] Package URL --- frontend/components/Editor.js | 2 +- frontend/components/PkgStatusMark.js | 22 +++++++++++++--------- frontend/components/Popup.js | 6 +++++- src/packages/PkgCompat.jl | 21 +++++++++++++++++++++ src/webserver/Dynamic.jl | 2 ++ test/packages/PkgCompat.jl | 6 ++++++ 6 files changed, 48 insertions(+), 11 deletions(-) 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..430a732bf1 100644 --- a/frontend/components/PkgStatusMark.js +++ b/frontend/components/PkgStatusMark.js @@ -23,6 +23,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,17 +31,21 @@ 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)) @@ -90,7 +95,7 @@ export const package_status = ({ nbpkg, package_name, available_versions, is_dis } } - 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 +108,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 +159,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..ece6054b12 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 library_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, }) ) } @@ -275,6 +278,7 @@ const PkgPopup = ({ notebook, recent_event, clear_recent_event, disable_input }) }} >📄 + ❔ ❔ <${PkgTerminalView} value=${terminal_value ?? "Loading..."} /> 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() From f522ea7ede6819c57d01592ad3ec19d899a529fd Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Fri, 11 Oct 2024 09:30:37 +0200 Subject: [PATCH 2/2] asdf --- frontend/components/PkgStatusMark.js | 16 +++++++++++----- frontend/components/Popup.js | 3 +-- frontend/editor.css | 8 ++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/frontend/components/PkgStatusMark.js b/frontend/components/PkgStatusMark.js index 430a732bf1..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()) @@ -50,6 +51,8 @@ export const package_status = ({ nbpkg, package_name, available_versions, is_dis 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" @@ -59,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) } @@ -89,7 +95,7 @@ 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.` } } diff --git a/frontend/components/Popup.js b/frontend/components/Popup.js index ece6054b12..2c48b47ad5 100644 --- a/frontend/components/Popup.js +++ b/frontend/components/Popup.js @@ -15,7 +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 library_icon = new URL("https://cdn.jsdelivr.net/gh/ionic-team/ionicons@5.5.1/src/svg/open-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 @@ -278,7 +278,6 @@ const PkgPopup = ({ notebook, recent_event, clear_recent_event, disable_input }) }} >📄 - ❔ ❔ <${PkgTerminalView} value=${terminal_value ?? "Loading..."} /> 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);