diff --git a/src/global/url.ml b/src/global/url.ml index 244b7edd98..dd3d31cfec 100644 --- a/src/global/url.ml +++ b/src/global/url.ml @@ -6,6 +6,7 @@ let packages_autocomplete_fragment = "/packages/autocomplete" module Package : sig val overview : ?hash:string -> ?version:string -> string -> string + val versions : ?hash:string -> ?version:string -> string -> string val documentation : ?hash:string -> ?version:string -> ?page:string -> string -> string @@ -22,6 +23,7 @@ end = struct with_hash hash ^ "/" ^ name ^ with_version version ^ page let overview ?hash ?version = base ?hash ?version "" + let versions ?hash ?version = base ?hash ?version "/versions" let documentation ?hash ?version ?(page = "index.html") = base ?hash ?version ("/doc/" ^ page) diff --git a/src/ocamlorg_frontend/components/icons.eml b/src/ocamlorg_frontend/components/icons.eml index eb1112d05f..e9644381d5 100644 --- a/src/ocamlorg_frontend/components/icons.eml +++ b/src/ocamlorg_frontend/components/icons.eml @@ -26,6 +26,11 @@ let arrow_top_right_on_square class_ = +let bars_3 class_ = + + + + let beaker class_ =
diff --git a/src/ocamlorg_frontend/css/styles.css b/src/ocamlorg_frontend/css/styles.css index e458d67a05..005668ebab 100644 --- a/src/ocamlorg_frontend/css/styles.css +++ b/src/ocamlorg_frontend/css/styles.css @@ -120,6 +120,10 @@ body { word-wrap: break-word; } +.prose { + word-wrap: break-word; +} + .prose [id] { scroll-margin-top: 2rem; } diff --git a/src/ocamlorg_frontend/dune b/src/ocamlorg_frontend/dune index 8678dd17a2..43b60bc2c7 100644 --- a/src/ocamlorg_frontend/dune +++ b/src/ocamlorg_frontend/dune @@ -141,6 +141,14 @@ %{dep:package_documentation.eml} --workspace %{workspace_root}))) + (rule + (target package_versions.ml) + (action + (run + %{bin:dream_eml} + %{dep:package_versions.eml} + --workspace + %{workspace_root}))) (rule (target packages.ml) (action diff --git a/src/ocamlorg_frontend/ocamlorg_frontend.ml b/src/ocamlorg_frontend/ocamlorg_frontend.ml index 4c0e57cebf..54ebc4d5d0 100644 --- a/src/ocamlorg_frontend/ocamlorg_frontend.ml +++ b/src/ocamlorg_frontend/ocamlorg_frontend.ml @@ -29,6 +29,7 @@ let package_overview_file = Package_overview.render_file let packages_autocomplete_fragment = Packages_autocomplete_fragment.render let packages = Packages.render let packages_search = Packages_search.render +let package_versions = Package_versions.render let page = Page.render let papers = Papers.render let platform = Platform.render diff --git a/src/ocamlorg_frontend/package.ml b/src/ocamlorg_frontend/package.ml index 56d7f5cd95..b5d2b52b5e 100644 --- a/src/ocamlorg_frontend/package.ml +++ b/src/ocamlorg_frontend/package.ml @@ -1,13 +1,18 @@ type version = Latest | Specific of string type documentation_status = Success | Failure | Unknown +type version_with_publication_date = { + version: string; + publication: float; +} + type package = { name : string; synopsis : string; description : string; license : string; version : version; - versions : string list; + versions : version_with_publication_date list; latest_version : string; tags : string list; rev_deps : string list; diff --git a/src/ocamlorg_frontend/pages/package_overview.eml b/src/ocamlorg_frontend/pages/package_overview.eml index 394853b882..e51857b58f 100644 --- a/src/ocamlorg_frontend/pages/package_overview.eml +++ b/src/ocamlorg_frontend/pages/package_overview.eml @@ -70,6 +70,7 @@ in <%s! side_box_link ~icon_html:(Icons.license "h-4 w-4 mr-2 inline-block") ~href:(Url.Package.file package.name ?version ~filepath:(license_filename ^ ".html")) ~title:( package.license ^ " License") %> <% | _ -> ()); %> <%s! side_box_link ~icon_html:(Icons.edit "h-4 w-4 mr-2 inline-block") ~href:(Url.github_opam_file package.name specific_version) ~title:"Edit opam file" %> + <%s! side_box_link ~icon_html:(Icons.tag "h-4 w-4 mr-2 inline-block") ~href:(Url.Package.file package.name ~filepath:("versions")) ~title: ( "Versions (" ^ string_of_int (List.length package.versions) ^ ")") %>

Authors

diff --git a/src/ocamlorg_frontend/pages/package_versions.eml b/src/ocamlorg_frontend/pages/package_versions.eml new file mode 100644 index 0000000000..063e0986eb --- /dev/null +++ b/src/ocamlorg_frontend/pages/package_versions.eml @@ -0,0 +1,50 @@ +let render +(package : Package.package) += +Layout.render +~title:(Printf.sprintf "%s Versions" package.name) +~description:"Package Versions" @@ +let version = Package.specific_version package in +
+
+ <%s! Icons.arrow_left "h-6 w-6 text-primary"; %> +

<%s package.name %> Versions (<%i List.length package.versions %>)

+
+
+ + + + + + + + + + + <% package.versions |> List.iter (fun (item: Package.version_with_publication_date) -> %> + + + + + + + <% ); %> + +
VersionRelease DateLinks
+ text-base md:mr-10"> + <%s item.version %> + + + <%s Utils.human_date_of_timestamp item.publication %> + + <%s! Icons.document "h-5 w-5"; %> Documentation +
+
+
\ No newline at end of file diff --git a/src/ocamlorg_package/lib/ocamlorg_package.ml b/src/ocamlorg_package/lib/ocamlorg_package.ml index bd6f565c85..8c6385c6b1 100644 --- a/src/ocamlorg_package/lib/ocamlorg_package.ml +++ b/src/ocamlorg_package/lib/ocamlorg_package.ml @@ -185,9 +185,16 @@ let get_by_name t name = |> Option.map Version.Map.bindings |> Option.map (List.map (fun (version, info) -> { name; version; info })) +type version_with_publication_date = { + version : Version.t; + publication: float; +} + let get_versions t name = t.packages |> Name.Map.find_opt name - |> Option.map (fun p -> p |> Version.Map.bindings |> List.rev_map fst) + |> Option.map (fun p -> p |> Version.Map.bindings |> List.map (fun (version, info) -> { version; publication = info.Info.publication})) + |> Option.value ~default:[] + |> List.sort (fun v1 v2 -> Version.compare v2.version v1.version) let get_latest t name = get_latest' t.packages name @@ -404,8 +411,8 @@ let latest_documented_version t name = | None -> aux (List.tl vlist)) in match get_versions t name with - | None -> Lwt.return None - | Some vlist -> aux vlist + | [] -> Lwt.return None + | vlist -> aux (vlist |> List.map (fun v -> v.version)) let is_latest_version t name version = match get_latest t name with diff --git a/src/ocamlorg_package/lib/ocamlorg_package.mli b/src/ocamlorg_package/lib/ocamlorg_package.mli index b78ae38e17..3e74494e7f 100644 --- a/src/ocamlorg_package/lib/ocamlorg_package.mli +++ b/src/ocamlorg_package/lib/ocamlorg_package.mli @@ -167,7 +167,12 @@ val stats : state -> Statistics.t option val get_by_name : state -> Name.t -> t list option (** Get the list of packages with the given name. *) -val get_versions : state -> Name.t -> Version.t list option +type version_with_publication_date = { + version : Version.t; + publication: float; +} + +val get_versions : state -> Name.t -> version_with_publication_date list (** Get the list of versions for a package name, newest coming first. *) val get_latest : state -> Name.t -> t option diff --git a/src/ocamlorg_web/lib/handler.ml b/src/ocamlorg_web/lib/handler.ml index 931b225322..e598e1dfe8 100644 --- a/src/ocamlorg_web/lib/handler.ml +++ b/src/ocamlorg_web/lib/handler.ml @@ -78,7 +78,6 @@ let changelog req = Data.Changelog.all |> List.concat_map (fun (change : Data.Changelog.t) -> change.tags) |> List.sort_uniq String.compare - |> List.sort_uniq String.compare in let changes = match current_tag with @@ -472,9 +471,7 @@ module Package_helper = struct (** Query all the versions of a package. *) let versions state name = Ocamlorg_package.get_versions state name - |> Option.value ~default:[] - |> List.sort (Fun.flip Ocamlorg_package.Version.compare) - |> List.map Ocamlorg_package.Version.to_string + |> List.map (fun (v: Ocamlorg_package.version_with_publication_date) -> Ocamlorg_frontend.Package.{version = Ocamlorg_package.Version.to_string v.version; publication = v.publication}) let frontend_package ?on_latest_url state (package : Ocamlorg_package.t) : Ocamlorg_frontend.Package.package = @@ -788,6 +785,14 @@ let package_overview t kind req = (Ocamlorg_frontend.package_overview ~sidebar_data ~readme ~search_index_digest ~toc ~deps_and_conflicts frontend_package) +let package_versions t _kind req = + let name = Ocamlorg_package.Name.of_string @@ Dream.param req "name" in + let version_from_url = Dream.param req "version" in + let? _package, frontend_package = + Package_helper.of_name_version t name version_from_url + in + Dream.html (Ocamlorg_frontend.package_versions frontend_package) + let package_documentation t kind req = let name = Ocamlorg_package.Name.of_string @@ Dream.param req "name" in let version_from_url = Dream.param req "version" in diff --git a/src/ocamlorg_web/lib/router.ml b/src/ocamlorg_web/lib/router.ml index 6f70397712..b9b21188f5 100644 --- a/src/ocamlorg_web/lib/router.ml +++ b/src/ocamlorg_web/lib/router.ml @@ -77,6 +77,12 @@ let package_route t = Dream.get (Url.Package.overview ~hash:":hash" ":name" ~version:":version") ((Handler.package_overview t) Handler.Universe); + Dream.get + (Url.Package.versions ":name" ~version:":version") + ((Handler.package_versions t) Handler.Universe); + Dream.get + (Url.Package.versions ~hash:":hash" ":name" ~version:":version") + ((Handler.package_versions t) Handler.Universe); Dream.get (Url.Package.documentation ":name" ~version:":version" ~page:"**") ((Handler.package_documentation t) Handler.Package);