docs(detached-note): add comprehensive API reference and user guide
Some checks failed
Build and Release / Create Release (push) Successful in 0s
Build and Release / Unit Tests (push) Successful in 3m19s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 4m39s
Build and Release / Lint (push) Successful in 4m46s
Build and Release / Build Binary (linux/arm64) (push) Has been cancelled
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, darwin, macos) (push) Has been cancelled
Build and Release / Build Binaries (arm64, darwin, macos) (push) Has been cancelled
Some checks failed
Build and Release / Create Release (push) Successful in 0s
Build and Release / Unit Tests (push) Successful in 3m19s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 4m39s
Build and Release / Lint (push) Successful in 4m46s
Build and Release / Build Binary (linux/arm64) (push) Has been cancelled
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, darwin, macos) (push) Has been cancelled
Build and Release / Build Binaries (arm64, darwin, macos) (push) Has been cancelled
Add API.md (3200+ lines) with complete REST API documentation covering authentication, repository management, issues, pull requests, organizations, package registry, Actions, and Vault APIs. Includes code examples and error handling. Add GUIDE.md with user-focused documentation for getting started, repository operations, collaboration workflows, and CI/CD setup. Implement documentation tab in repository view with automatic detection and rendering of API.md and GUIDE.md files alongside README. Add locale strings and template for doc tab navigation.
This commit is contained in:
@@ -1004,6 +1004,8 @@
|
|||||||
"repo.readme": "README",
|
"repo.readme": "README",
|
||||||
"repo.readme_helper": "Select a README file template.",
|
"repo.readme_helper": "Select a README file template.",
|
||||||
"repo.readme_helper_desc": "This is the place where you can write a complete description for your project.",
|
"repo.readme_helper_desc": "This is the place where you can write a complete description for your project.",
|
||||||
|
"repo.guide": "User Guide",
|
||||||
|
"repo.api_doc": "API",
|
||||||
"repo.auto_init": "Initialize Repository (Adds .gitignore, License and README)",
|
"repo.auto_init": "Initialize Repository (Adds .gitignore, License and README)",
|
||||||
"repo.trust_model_helper": "Select trust model for signature verification. Possible options are:",
|
"repo.trust_model_helper": "Select trust model for signature verification. Possible options are:",
|
||||||
"repo.trust_model_helper_collaborator": "Collaborator: Trust signatures by collaborators",
|
"repo.trust_model_helper_collaborator": "Collaborator: Trust signatures by collaborators",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"code.gitcaddy.com/server/v3/models/db"
|
"code.gitcaddy.com/server/v3/models/db"
|
||||||
git_model "code.gitcaddy.com/server/v3/models/git"
|
git_model "code.gitcaddy.com/server/v3/models/git"
|
||||||
|
"code.gitcaddy.com/server/v3/models/renderhelper"
|
||||||
repo_model "code.gitcaddy.com/server/v3/models/repo"
|
repo_model "code.gitcaddy.com/server/v3/models/repo"
|
||||||
unit_model "code.gitcaddy.com/server/v3/models/unit"
|
unit_model "code.gitcaddy.com/server/v3/models/unit"
|
||||||
user_model "code.gitcaddy.com/server/v3/models/user"
|
user_model "code.gitcaddy.com/server/v3/models/user"
|
||||||
@@ -23,6 +24,7 @@ import (
|
|||||||
"code.gitcaddy.com/server/v3/modules/httplib"
|
"code.gitcaddy.com/server/v3/modules/httplib"
|
||||||
"code.gitcaddy.com/server/v3/modules/json"
|
"code.gitcaddy.com/server/v3/modules/json"
|
||||||
"code.gitcaddy.com/server/v3/modules/log"
|
"code.gitcaddy.com/server/v3/modules/log"
|
||||||
|
"code.gitcaddy.com/server/v3/modules/markup/markdown"
|
||||||
"code.gitcaddy.com/server/v3/modules/plugins"
|
"code.gitcaddy.com/server/v3/modules/plugins"
|
||||||
repo_module "code.gitcaddy.com/server/v3/modules/repository"
|
repo_module "code.gitcaddy.com/server/v3/modules/repository"
|
||||||
"code.gitcaddy.com/server/v3/modules/setting"
|
"code.gitcaddy.com/server/v3/modules/setting"
|
||||||
@@ -259,6 +261,62 @@ func isGalleryImageFile(filename string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepareHomeDocTab loads a markdown doc file for a named tab on the repo home page.
|
||||||
|
// keyPrefix is used to namespace context data (e.g. "Guide" → "GuideTabExist", "GuideTabContent").
|
||||||
|
func prepareHomeDocTab(ctx *context.Context, filename, keyPrefix string) {
|
||||||
|
ctx.Data[keyPrefix+"TabExist"] = false
|
||||||
|
|
||||||
|
if ctx.Repo.Repository.IsEmpty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commit := ctx.Repo.Commit
|
||||||
|
if commit == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := commit.GetTreeEntryByPath(filename)
|
||||||
|
if err != nil || entry.IsDir() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data[keyPrefix+"TabExist"] = true
|
||||||
|
ctx.Data[keyPrefix+"TabFileName"] = filename
|
||||||
|
|
||||||
|
// Load content
|
||||||
|
content, err := entry.Blob().GetBlobContent(setting.UI.MaxDisplayFileSize)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("prepareHomeDocTab(%s): GetBlobContent: %v", filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render markdown using the full markup pipeline
|
||||||
|
rctx := renderhelper.NewRenderContextRepoFile(ctx, ctx.Repo.Repository, renderhelper.RepoFileOptions{
|
||||||
|
CurrentRefPath: ctx.Repo.RefTypeNameSubURL(),
|
||||||
|
CurrentTreePath: ".",
|
||||||
|
}).WithMarkupType("markdown").WithRelativePath(filename)
|
||||||
|
|
||||||
|
rendered, err := markdown.RenderString(rctx, content)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("prepareHomeDocTab(%s): RenderString: %v", filename, err)
|
||||||
|
ctx.Data[keyPrefix+"TabContent"] = content
|
||||||
|
ctx.Data[keyPrefix+"TabIsMarkdown"] = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data[keyPrefix+"TabContent"] = rendered
|
||||||
|
ctx.Data[keyPrefix+"TabIsMarkdown"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepareHomeGuideTab loads GUIDE.md for the User Guide tab
|
||||||
|
func prepareHomeGuideTab(ctx *context.Context) {
|
||||||
|
prepareHomeDocTab(ctx, "GUIDE.md", "Guide")
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepareHomeAPIDocTab loads API.md for the API tab
|
||||||
|
func prepareHomeAPIDocTab(ctx *context.Context) {
|
||||||
|
prepareHomeDocTab(ctx, "API.md", "APIDoc")
|
||||||
|
}
|
||||||
|
|
||||||
func prepareToRenderDirectory(ctx *context.Context) {
|
func prepareToRenderDirectory(ctx *context.Context) {
|
||||||
entries := renderDirectoryFiles(ctx, 1*time.Second)
|
entries := renderDirectoryFiles(ctx, 1*time.Second)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
@@ -594,6 +652,8 @@ func Home(ctx *context.Context) {
|
|||||||
prepareUpstreamDivergingInfo,
|
prepareUpstreamDivergingInfo,
|
||||||
prepareHomeSidebarLicenses,
|
prepareHomeSidebarLicenses,
|
||||||
prepareHomeLicenseTab,
|
prepareHomeLicenseTab,
|
||||||
|
prepareHomeGuideTab,
|
||||||
|
prepareHomeAPIDocTab,
|
||||||
prepareHomeGalleryTab,
|
prepareHomeGalleryTab,
|
||||||
prepareHomeSidebarCitationFile(entry),
|
prepareHomeSidebarCitationFile(entry),
|
||||||
prepareHomeSidebarLanguageStats,
|
prepareHomeSidebarLanguageStats,
|
||||||
|
|||||||
@@ -130,43 +130,64 @@
|
|||||||
{{template "repo/code/upstream_diverging_info" .}}
|
{{template "repo/code/upstream_diverging_info" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{template "repo/view_list" .}}
|
{{template "repo/view_list" .}}
|
||||||
{{/* Tabs for Readme, License, Gallery - only shown at repo root */}}
|
{{/* Tabs for Readme, Guide, API, License, Gallery - only shown at repo root */}}
|
||||||
{{if and $isTreePathRoot (or (and .ReadmeExist (or .IsMarkup .IsPlainText)) .LicenseTabExist .GalleryTabExist)}}
|
{{$hasReadme := and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
||||||
|
{{if and $isTreePathRoot (or $hasReadme .GuideTabExist .APIDocTabExist .LicenseTabExist .GalleryTabExist)}}
|
||||||
<div class="ui top attached tabular menu" id="repo-home-tabs">
|
<div class="ui top attached tabular menu" id="repo-home-tabs">
|
||||||
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
{{if $hasReadme}}
|
||||||
<a class="active item" data-tab="readme">
|
<a class="active item" data-tab="readme">
|
||||||
{{svg "octicon-book" 16}} {{ctx.Locale.Tr "repo.readme"}}
|
{{svg "octicon-book" 16}} {{ctx.Locale.Tr "repo.readme"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if .GuideTabExist}}
|
||||||
|
<a class="{{if not $hasReadme}}active {{end}}item" data-tab="guide">
|
||||||
|
{{svg "octicon-mortar-board" 16}} {{ctx.Locale.Tr "repo.guide"}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
{{if .APIDocTabExist}}
|
||||||
|
<a class="{{if and (not $hasReadme) (not .GuideTabExist)}}active {{end}}item" data-tab="apidoc">
|
||||||
|
{{svg "octicon-plug" 16}} {{ctx.Locale.Tr "repo.api_doc"}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
{{if .LicenseTabExist}}
|
{{if .LicenseTabExist}}
|
||||||
<a class="{{if not (and .ReadmeExist (or .IsMarkup .IsPlainText))}}active {{end}}item" data-tab="license">
|
<a class="{{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist)}}active {{end}}item" data-tab="license">
|
||||||
{{svg "octicon-law" 16}} {{ctx.Locale.Tr "repo.license"}}
|
{{svg "octicon-law" 16}} {{ctx.Locale.Tr "repo.license"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .GalleryTabExist}}
|
{{if .GalleryTabExist}}
|
||||||
<a class="{{if and (not (and .ReadmeExist (or .IsMarkup .IsPlainText))) (not .LicenseTabExist)}}active {{end}}item" data-tab="gallery">
|
<a class="{{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist) (not .LicenseTabExist)}}active {{end}}item" data-tab="gallery">
|
||||||
{{svg "octicon-image" 16}} {{ctx.Locale.Tr "repo.gallery"}}
|
{{svg "octicon-image" 16}} {{ctx.Locale.Tr "repo.gallery"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached segment tw-p-0">
|
<div class="ui bottom attached segment tw-p-0">
|
||||||
{{if and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
{{if $hasReadme}}
|
||||||
<div class="ui active tab" data-tab="readme">
|
<div class="ui active tab" data-tab="readme">
|
||||||
{{template "repo/view_file" .}}
|
{{template "repo/view_file" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if .GuideTabExist}}
|
||||||
|
<div class="ui {{if not $hasReadme}}active {{end}}tab" data-tab="guide">
|
||||||
|
{{template "repo/view_doc_tab" dict "ctxData" . "FileName" .GuideTabFileName "Content" .GuideTabContent "IsMarkdown" .GuideTabIsMarkdown "Icon" "octicon-mortar-board"}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if .APIDocTabExist}}
|
||||||
|
<div class="ui {{if and (not $hasReadme) (not .GuideTabExist)}}active {{end}}tab" data-tab="apidoc">
|
||||||
|
{{template "repo/view_doc_tab" dict "ctxData" . "FileName" .APIDocTabFileName "Content" .APIDocTabContent "IsMarkdown" .APIDocTabIsMarkdown "Icon" "octicon-plug"}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
{{if .LicenseTabExist}}
|
{{if .LicenseTabExist}}
|
||||||
<div class="ui {{if not (and .ReadmeExist (or .IsMarkup .IsPlainText))}}active {{end}}tab" data-tab="license">
|
<div class="ui {{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist)}}active {{end}}tab" data-tab="license">
|
||||||
{{template "repo/view_license_tab" .}}
|
{{template "repo/view_license_tab" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .GalleryTabExist}}
|
{{if .GalleryTabExist}}
|
||||||
<div class="ui {{if and (not (and .ReadmeExist (or .IsMarkup .IsPlainText))) (not .LicenseTabExist)}}active {{end}}tab" data-tab="gallery">
|
<div class="ui {{if and (not $hasReadme) (not .GuideTabExist) (not .APIDocTabExist) (not .LicenseTabExist)}}active {{end}}tab" data-tab="gallery">
|
||||||
{{template "repo/view_gallery_tab" .}}
|
{{template "repo/view_gallery_tab" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else if and .ReadmeExist (or .IsMarkup .IsPlainText)}}
|
{{else if $hasReadme}}
|
||||||
{{/* Fallback: show README without tabs if it's the only content */}}
|
{{/* Fallback: show README without tabs if it's the only content */}}
|
||||||
{{template "repo/view_file" .}}
|
{{template "repo/view_file" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
27
templates/repo/view_doc_tab.tmpl
Normal file
27
templates/repo/view_doc_tab.tmpl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<div class="file-view code-view">
|
||||||
|
<div class="file-header tw-flex tw-items-center tw-justify-between">
|
||||||
|
<div class="file-header-left tw-flex tw-items-center">
|
||||||
|
{{svg .Icon 18 "tw-mr-2"}}
|
||||||
|
<strong>{{.FileName}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="file-header-right">
|
||||||
|
<a class="ui basic tiny button" href="{{.ctxData.RepoLink}}/src/{{.ctxData.RefTypeNameSubURL}}/{{.FileName}}">
|
||||||
|
{{svg "octicon-file" 14}} {{ctx.Locale.Tr "repo.view_file"}}
|
||||||
|
</a>
|
||||||
|
<a class="ui basic tiny button" href="{{.ctxData.RepoLink}}/raw/{{.ctxData.RefTypeNameSubURL}}/{{.FileName}}">
|
||||||
|
{{svg "octicon-code" 14}} {{ctx.Locale.Tr "repo.file_raw"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="file-body tw-p-4 tw-text-base">
|
||||||
|
{{if .IsMarkdown}}
|
||||||
|
<div class="markup markdown">
|
||||||
|
{{.Content}}
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="file-content plain-text">
|
||||||
|
<pre>{{.Content}}</pre>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user