internal/frontend: add fetchMainDetails
Logic for rendering the main unit page (which is not shared with other
tabs) is factored out into a fetchMainPage function and MainDetails
struct. This means that GetUnit and GetImportedBy are no longer
called unnecessarily when fetching data for non-main page tabs.
Data for MainDetails is now stored on UnitPage.Details, as is the case
with other tabs. A couple of fields are added/changed:
* LastCommitTime is renamed to CommitTime, since they mean the same thing
and the latter is less verbose.
* IsPackage is added, which is used to determine whether a documentation
section should be shown, even if the documentation is empty.
* NumImports is added, which is used to display the number of imports
for given package.
UnitPage.Unit is changed to a UnitMeta type, since other fields on Unit
are no longer needed and UnitMeta is more explicit.
Change-Id: I7d5f4de867678c60d697fe9559416f3171f2d15c
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/261721
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/content/static/html/helpers/_unit_fixed_header.tmpl b/content/static/html/helpers/_unit_fixed_header.tmpl
index 7b5cac9..8d19a54 100644
--- a/content/static/html/helpers/_unit_fixed_header.tmpl
+++ b/content/static/html/helpers/_unit_fixed_header.tmpl
@@ -45,11 +45,11 @@
</span>
<span class="UnitHeaderFixed-detailItem UnitHeaderFixed-detailItem--md">
<img height="16px" width="16px" src="/static/img/pkg-icon-circularArrows_16x16.svg" alt="">
- {{.LastCommitTime}}
+ {{.Details.CommitTime}}
</span>
<span class="UnitHeaderFixed-detailItem UnitHeaderFixed-detailItem--md">
<img height="16px" width="16px" src="/static/img/pkg-icon-scale_16x16.svg" alt="">
- {{range $i, $e := .Licenses}}
+ {{range $i, $e := .Details.Licenses}}
{{if $i}}, {{end}}
<a href="{{$.URLPath}}?tab=licenses#{{.Anchor}}" tabindex="-1">{{$e.Type}}</a>
{{else}}
@@ -63,13 +63,13 @@
<span class="UnitHeaderFixed-detailItem UnitHeaderFixed-detailItem--lg">
<img height="16px" width="16px" src="/static/img/pkg-icon-boxClosed_16x16.svg" alt="">
<a href="{{$.URLPath}}?tab=imports" tabindex="-1">
- {{len .Unit.Imports}} <span>Imports</span>
+ {{.Details.NumImports}} <span>Imports</span>
</a>
</span>
<span class="UnitHeaderFixed-detailItem UnitHeaderFixed-detailItem--lg">
<img height="16px" width="16px" src="/static/img/pkg-icon-boxClosed_16x16.svg" alt="">
<a href="{{$.URLPath}}?tab=importedby" tabindex="-1">
- {{.ImportedByCount}} <span>Imported by</span>
+ {{.Details.ImportedByCount}} <span>Imported by</span>
</a>
</span>
{{end}}
diff --git a/content/static/html/helpers/_unit_header.tmpl b/content/static/html/helpers/_unit_header.tmpl
index 64f006b..cd09a81 100644
--- a/content/static/html/helpers/_unit_header.tmpl
+++ b/content/static/html/helpers/_unit_header.tmpl
@@ -57,13 +57,13 @@
</span>
<span class="UnitHeader-detailItem">
<img height="16px" width="16px" src="/static/img/pkg-icon-circularArrows_16x16.svg" alt="">
- {{.LastCommitTime}}
+ {{.Details.CommitTime}}
</span>
<span class="UnitHeader-detailItem">
<img height="16px" width="16px" src="/static/img/pkg-icon-scale_16x16.svg" alt="">
- {{if .Licenses}}
+ {{if .Details.Licenses}}
<a href="{{$.URLPath}}?tab=licenses">
- {{range $i, $e := .Licenses}}
+ {{range $i, $e := .Details.Licenses}}
{{if $i}}, {{end}} {{$e.Type}}
{{end}}
</a>
@@ -76,13 +76,13 @@
<span class="UnitHeader-detailItem">
<img height="16px" width="16px" src="/static/img/pkg-icon-boxClosed_16x16.svg" alt="">
<a href="{{$.URLPath}}?tab=imports">
- {{len .Unit.Imports}} <span>Imports</span>
+ {{.Details.NumImports}} <span>Imports</span>
</a>
</span>
<span class="UnitHeader-detailItem">
<img height="16px" width="16px" src="/static/img/pkg-icon-boxClosed_16x16.svg" alt="">
<a href="{{$.URLPath}}?tab=importedby">
- {{.ImportedByCount}} <span>Imported by</span>
+ {{.Details.ImportedByCount}} <span>Imported by</span>
</a>
</span>
{{end}}
diff --git a/content/static/html/helpers/_unit_outline.tmpl b/content/static/html/helpers/_unit_outline.tmpl
index 655ef11..aea5f85 100644
--- a/content/static/html/helpers/_unit_outline.tmpl
+++ b/content/static/html/helpers/_unit_outline.tmpl
@@ -19,7 +19,7 @@
<div class="UnitOutline-panel js-accordionPanel"
id="readme-panel" role="region" aria-labelledby="readme-accordion" aria-hidden="true"></div>
{{end}}
- {{if (or .DocOutline.String .Unit.IsPackage)}}
+ {{if .IsPackage}}
<a class="UnitOutline-accordion js-accordionTrigger" href="#section-documentation"
role="button" aria-expanded="false" aria-controls="outline-panel" id="outline-accordion">
Documentation
diff --git a/content/static/html/pages/unit_details.tmpl b/content/static/html/pages/unit_details.tmpl
index 10474cc..c38e607 100644
--- a/content/static/html/pages/unit_details.tmpl
+++ b/content/static/html/pages/unit_details.tmpl
@@ -10,25 +10,25 @@
{{define "unit_content"}}
<div class="UnitDetails">
- {{.MobileOutline}}
+ {{.Details.MobileOutline}}
<div class="UnitDetails-outline" role="navigation"
aria-label="{{if eq .PageType "std"}}module
{{else}}{{.PageType}}{{end}}details navigation">
- {{block "unit_outline" .}}{{end}}
+ {{block "unit_outline" .Details}}{{end}}
</div>
<div class="UnitDetails-content" role="main">
{{if .CanShowDetails}}
- {{if .Readme.String}}
- {{block "unit_readme" .}}{{end}}
+ {{if .Details.Readme.String}}
+ {{block "unit_readme" .Details}}{{end}}
{{end}}
- {{if (or .DocBody.String .Unit.IsPackage)}}
- {{block "unit_doc" .}}{{end}}
+ {{if .Details.IsPackage}}
+ {{block "unit_doc" .Details}}{{end}}
{{end}}
- {{if .SourceFiles}}
- {{block "unit_files" .}}{{end}}
+ {{if .Details.SourceFiles}}
+ {{block "unit_files" .Details}}{{end}}
{{end}}
- {{if (or .Subdirectories .NestedModules)}}
- {{block "unit_directories" .}}{{end}}
+ {{if (or .Details.Subdirectories .Details.NestedModules)}}
+ {{block "unit_directories" .Details}}{{end}}
{{end}}
{{else}}
<h2>“{{.UnitContentName}}” not displayed due to license restrictions.</h2>
diff --git a/internal/frontend/unit.go b/internal/frontend/unit.go
index bdc3aba..f776108 100644
--- a/internal/frontend/unit.go
+++ b/internal/frontend/unit.go
@@ -9,17 +9,14 @@
"net/http"
"path"
"sort"
- "strconv"
"strings"
"github.com/google/safehtml"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/experiment"
- "golang.org/x/pkgsite/internal/godoc"
"golang.org/x/pkgsite/internal/log"
"golang.org/x/pkgsite/internal/middleware"
- "golang.org/x/pkgsite/internal/postgres"
"golang.org/x/pkgsite/internal/stdlib"
)
@@ -27,14 +24,7 @@
type UnitPage struct {
basePage
// Unit is the unit for this page.
- Unit *internal.Unit
-
- // NestedModules are nested modules relative to the path for the unit.
- NestedModules []*NestedModule
-
- // Subdirectories are packages in subdirectories relative to the path for
- // the unit.
- Subdirectories []*Subdirectory
+ Unit *internal.UnitMeta
// Breadcrumb contains data used to render breadcrumb UI elements.
Breadcrumb breadcrumb
@@ -51,12 +41,6 @@
// the canonical url for that path would be /my.module@v1.5.2/pkg
CanonicalURLPath string
- // Licenses contains license metadata used in the header.
- Licenses []LicenseMetadata
-
- // Elapsed time since this version was committed.
- LastCommitTime string
-
// The version string formatted for display.
DisplayVersion string
@@ -81,12 +65,6 @@
// UnitContentName is the display name of the selected unit content template".
UnitContentName string
- // Readme is the rendered readme HTML.
- Readme safehtml.HTML
-
- // ExpandReadme is holds the expandable readme state.
- ExpandReadme bool
-
// Tabs contains data to render the varioius tabs on each details page.
Tabs []TabSettings
@@ -95,39 +73,6 @@
// Details contains data specific to the type of page being rendered.
Details interface{}
-
- // ImportedByCount is the number of packages that import this path.
- // When the count is > limit it will read as 'limit+'. This field
- // is not supported when using a datasource proxy.
- ImportedByCount string
-
- DocBody safehtml.HTML
- DocOutline safehtml.HTML
- MobileOutline safehtml.HTML
-
- // SourceFiles contains .go files for the package.
- SourceFiles []*File
-}
-
-// File is a source file for a package.
-type File struct {
- Name string
- URL string
-}
-
-// NestedModule is a nested module relative to the path of a given unit.
-// This content is used in the Directories section of the unit page.
-type NestedModule struct {
- Suffix string // suffix after the unit path
- URL string
-}
-
-// Subdirectory is a package in a subdirectory relative to the path of a given
-// unit. This content is used in the Directories section of the unit page.
-type Subdirectory struct {
- Suffix string
- URL string
- Synopsis string
}
var (
@@ -175,71 +120,6 @@
func (s *Server) serveUnitPage(ctx context.Context, w http.ResponseWriter, r *http.Request,
ds internal.DataSource, um *internal.UnitMeta, requestedVersion string) (err error) {
defer derrors.Wrap(&err, "serveUnitPage(ctx, w, r, ds, %v, %q)", um, requestedVersion)
- unit, err := ds.GetUnit(ctx, um, internal.AllFields)
- if err != nil {
- return err
- }
-
- // importedByCount is not supported when using a datasource proxy.
- importedByCount := "0"
- db, ok := ds.(*postgres.DB)
- if ok {
- importedBy, err := db.GetImportedBy(ctx, um.Path, um.ModulePath, importedByLimit)
- if err != nil {
- return err
- }
- // If we reached the query limit, then we don't know the total
- // and we'll indicate that with a '+'. For example, if the limit
- // is 101 and we get 101 results, then we'll show '100+ Imported by'.
- importedByCount = strconv.Itoa(len(importedBy))
- if len(importedBy) == importedByLimit {
- importedByCount = strconv.Itoa(len(importedBy)-1) + "+"
- }
- }
-
- nestedModules, err := getNestedModules(ctx, ds, um)
- if err != nil {
- return err
- }
- subdirectories := getSubdirectories(um, unit.Subdirectories)
- if err != nil {
- return err
- }
- readme, err := readmeContent(ctx, um, unit.Readme)
- if err != nil {
- return err
- }
-
- var (
- docBody, docOutline, mobileOutline safehtml.HTML
- files []*File
- )
- if unit.Documentation != nil {
- docHTML := getHTML(ctx, unit)
- // TODO: Deprecate godoc.Parse. The sidenav and body can
- // either be rendered using separate functions, or all this content can
- // be passed to the template via the UnitPage struct.
- b, err := godoc.Parse(docHTML, godoc.BodySection)
- if err != nil {
- return err
- }
- docBody = b
- o, err := godoc.Parse(docHTML, godoc.SidenavSection)
- if err != nil {
- return err
- }
- docOutline = o
- m, err := godoc.Parse(docHTML, godoc.SidenavMobileSection)
- if err != nil {
- return err
- }
- mobileOutline = m
-
- files, err = sourceFiles(unit)
- if err != nil {
- return err
- }
- }
tab := r.FormValue("tab")
if tab == "" {
@@ -257,16 +137,13 @@
basePage := s.newBasePage(r, title)
basePage.AllowWideContent = true
canShowDetails := um.IsRedistributable || tabSettings.AlwaysShowDetails
- _, expandReadme := r.URL.Query()["readme"]
page := UnitPage{
- basePage: basePage,
- Unit: unit,
- Subdirectories: subdirectories,
- NestedModules: nestedModules,
- Breadcrumb: displayBreadcrumb(um, requestedVersion),
- Title: title,
- Tabs: unitTabs,
- SelectedTab: tabSettings,
+ basePage: basePage,
+ Unit: um,
+ Breadcrumb: displayBreadcrumb(um, requestedVersion),
+ Title: title,
+ Tabs: unitTabs,
+ SelectedTab: tabSettings,
URLPath: constructPackageURL(
um.Path,
um.ModulePath,
@@ -277,8 +154,6 @@
um.ModulePath,
linkVersion(um.Version, um.ModulePath),
),
- Licenses: transformLicenseMetadata(um.Licenses),
- LastCommitTime: elapsedTime(um.CommitTime),
DisplayVersion: displayVersion(um.Version, um.ModulePath),
LinkVersion: linkVersion(um.Version, um.ModulePath),
LatestURL: constructPackageURL(um.Path, um.ModulePath, middleware.LatestMinorVersionPlaceholder),
@@ -286,23 +161,23 @@
PageType: pageType(um),
CanShowDetails: canShowDetails,
UnitContentName: tabSettings.DisplayName,
- Readme: readme,
- ExpandReadme: expandReadme,
- DocOutline: docOutline,
- DocBody: docBody,
- SourceFiles: files,
- MobileOutline: mobileOutline,
- ImportedByCount: importedByCount,
}
-
- if tab != tabDetails {
- packageDetails, err := fetchDetailsForPackage(r, tab, ds, um)
+ if tab == tabDetails {
+ _, expandReadme := r.URL.Query()["readme"]
+ d, err := fetchMainDetails(ctx, ds, um)
if err != nil {
return err
}
- page.Details = packageDetails
+ d.ExpandReadme = expandReadme
+ page.Details = d
}
-
+ if tab != tabDetails {
+ d, err := fetchDetailsForPackage(r, tab, ds, um)
+ if err != nil {
+ return err
+ }
+ page.Details = d
+ }
s.servePage(ctx, w, tabSettings.TemplateName, page)
return nil
}
diff --git a/internal/frontend/unit_main.go b/internal/frontend/unit_main.go
new file mode 100644
index 0000000..0ac8364
--- /dev/null
+++ b/internal/frontend/unit_main.go
@@ -0,0 +1,157 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package frontend
+
+import (
+ "context"
+ "strconv"
+
+ "github.com/google/safehtml"
+ "golang.org/x/pkgsite/internal"
+ "golang.org/x/pkgsite/internal/godoc"
+ "golang.org/x/pkgsite/internal/postgres"
+)
+
+// MainDetails contains data needed to render the unit template.
+type MainDetails struct {
+ // NestedModules are nested modules relative to the path for the unit.
+ NestedModules []*NestedModule
+
+ // Subdirectories are packages in subdirectories relative to the path for
+ // the unit.
+ Subdirectories []*Subdirectory
+
+ // Licenses contains license metadata used in the header.
+ Licenses []LicenseMetadata
+
+ // NumImports is the number of imports for the package.
+ NumImports int
+
+ // CommitTime is time that this version was published, or the time that
+ // has elapsed since this version was committed if it was done so recently.
+ CommitTime string
+
+ // Readme is the rendered readme HTML.
+ Readme safehtml.HTML
+
+ // ImportedByCount is the number of packages that import this path.
+ // When the count is > limit it will read as 'limit+'. This field
+ // is not supported when using a datasource proxy.
+ ImportedByCount string
+
+ DocBody safehtml.HTML
+ DocOutline safehtml.HTML
+ MobileOutline safehtml.HTML
+ IsPackage bool
+
+ // SourceFiles contains .go files for the package.
+ SourceFiles []*File
+
+ // ExpandReadme is holds the expandable readme state.
+ ExpandReadme bool
+}
+
+// File is a source file for a package.
+type File struct {
+ Name string
+ URL string
+}
+
+// NestedModule is a nested module relative to the path of a given unit.
+// This content is used in the Directories section of the unit page.
+type NestedModule struct {
+ Suffix string // suffix after the unit path
+ URL string
+}
+
+// Subdirectory is a package in a subdirectory relative to the path of a given
+// unit. This content is used in the Directories section of the unit page.
+type Subdirectory struct {
+ Suffix string
+ URL string
+ Synopsis string
+}
+
+func fetchMainDetails(ctx context.Context, ds internal.DataSource, um *internal.UnitMeta) (_ *MainDetails, err error) {
+ unit, err := ds.GetUnit(ctx, um, internal.AllFields)
+ if err != nil {
+ return nil, err
+ }
+
+ // importedByCount is not supported when using a datasource proxy.
+ importedByCount := "0"
+ db, ok := ds.(*postgres.DB)
+ if ok {
+ importedBy, err := db.GetImportedBy(ctx, um.Path, um.ModulePath, importedByLimit)
+ if err != nil {
+ return nil, err
+ }
+ // If we reached the query limit, then we don't know the total
+ // and we'll indicate that with a '+'. For example, if the limit
+ // is 101 and we get 101 results, then we'll show '100+ Imported by'.
+ importedByCount = strconv.Itoa(len(importedBy))
+ if len(importedBy) == importedByLimit {
+ importedByCount = strconv.Itoa(len(importedBy)-1) + "+"
+ }
+ }
+
+ nestedModules, err := getNestedModules(ctx, ds, um)
+ if err != nil {
+ return nil, err
+ }
+ subdirectories := getSubdirectories(um, unit.Subdirectories)
+ if err != nil {
+ return nil, err
+ }
+ readme, err := readmeContent(ctx, um, unit.Readme)
+ if err != nil {
+ return nil, err
+ }
+
+ var (
+ docBody, docOutline, mobileOutline safehtml.HTML
+ files []*File
+ )
+ if unit.Documentation != nil {
+ docHTML := getHTML(ctx, unit)
+ // TODO: Deprecate godoc.Parse. The sidenav and body can
+ // either be rendered using separate functions, or all this content can
+ // be passed to the template via the UnitPage struct.
+ b, err := godoc.Parse(docHTML, godoc.BodySection)
+ if err != nil {
+ return nil, err
+ }
+ docBody = b
+ o, err := godoc.Parse(docHTML, godoc.SidenavSection)
+ if err != nil {
+ return nil, err
+ }
+ docOutline = o
+ m, err := godoc.Parse(docHTML, godoc.SidenavMobileSection)
+ if err != nil {
+ return nil, err
+ }
+ mobileOutline = m
+
+ files, err = sourceFiles(unit)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &MainDetails{
+ NestedModules: nestedModules,
+ Subdirectories: subdirectories,
+ Licenses: transformLicenseMetadata(um.Licenses),
+ CommitTime: elapsedTime(um.CommitTime),
+ Readme: readme,
+ DocOutline: docOutline,
+ DocBody: docBody,
+ SourceFiles: files,
+ MobileOutline: mobileOutline,
+ NumImports: len(unit.Imports),
+ ImportedByCount: importedByCount,
+ IsPackage: unit.IsPackage(),
+ }, nil
+}