forked from tangled.org/core
this repo has no description

appview: add pages for tags and branches

Changed files
+456 -273
appview
knotserver
types
+12 -7
appview/pages/pages.go
···
}
type RepoIndexParams struct {
-
LoggedInUser *auth.User
-
RepoInfo RepoInfo
-
Active string
-
TagMap map[string][]string
-
Tags []*types.TagReference
-
CommitsTrunc []*object.Commit
+
LoggedInUser *auth.User
+
RepoInfo RepoInfo
+
Active string
+
TagMap map[string][]string
+
CommitsTrunc []*object.Commit
+
TagsTrunc []*types.TagReference
+
BranchesTrunc []types.Branch
types.RepoIndexResponse
HTMLReadme template.HTML
Raw bool
···
func (p *Pages) RepoLog(w io.Writer, params RepoLogParams) error {
params.Active = "overview"
-
return p.execute("repo/log", w, params)
+
return p.executeRepo("repo/log", w, params)
}
type RepoCommitParams struct {
···
type RepoBranchesParams struct {
LoggedInUser *auth.User
RepoInfo RepoInfo
+
Active string
types.RepoBranchesResponse
}
func (p *Pages) RepoBranches(w io.Writer, params RepoBranchesParams) error {
+
params.Active = "overview"
return p.executeRepo("repo/branches", w, params)
}
type RepoTagsParams struct {
LoggedInUser *auth.User
RepoInfo RepoInfo
+
Active string
types.RepoTagsResponse
}
func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error {
+
params.Active = "overview"
return p.executeRepo("repo/tags", w, params)
}
+50 -10
appview/pages/templates/repo/branches.html
···
{{ define "title" }}
-
branches | {{ .RepoInfo.FullName }}
+
branches · {{ .RepoInfo.FullName }}
{{ end }}
{{ define "repoContent" }}
-
<h3>branches</h3>
-
<div class="refs">
-
{{ range .Branches }}
-
<div>
-
<strong>{{ .Name }}</strong>
-
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ .Name }}/">browse</a>
-
<a href="/{{ $.RepoInfo.FullName }}/log/{{ .Name }}">log</a>
-
</div>
-
{{ end }}
+
<section>
+
<header class="font-bold text-sm mb-4 uppercase dark:text-white">
+
Branches
+
</header>
+
+
<div class="overflow-x-auto">
+
<table class="min-w-full table-auto">
+
<tbody>
+
{{ range .Branches }}
+
<tr>
+
<td class="whitespace-nowrap">
+
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ .Name | urlquery }}" class="no-underline hover:underline flex items-center gap-2">
+
<span>
+
{{ .Name }}
+
</span>
+
{{ if .IsDefault }}
+
<span class="
+
text-sm rounded
+
bg-gray-100 dark:bg-gray-700 text-black dark:text-white
+
font-mono
+
px-2 mx-1/2
+
inline-flex items-center
+
">
+
default
+
</span>
+
{{ end }}
+
</a>
+
</td>
+
<td class="whitespace-nowrap hidden md:table-cell">
+
{{ if .Commit }}
+
<a href="/{{ $.RepoInfo.FullName }}/commits/{{ .Name | urlquery }}" class="font-mono">{{ slice .Commit.Hash.String 0 8 }}</a>
+
{{ end }}
+
</td>
+
<td class="whitespace-nowrap hidden md:table-cell">
+
{{ if .Commit }}
+
{{ $messageParts := splitN .Commit.Message "\n\n" 2 }}
+
{{ index $messageParts 0 }}
+
{{ end }}
+
</td>
+
<td class="whitespace-nowrap">
+
{{ if .Commit }}
+
{{ .Commit.Author.When | timeFmt }}
+
{{ end }}
+
</td>
+
</tr>
+
{{ end }}
+
</tbody>
+
</table>
</div>
+
</section>
{{ end }}
+178 -179
appview/pages/templates/repo/index.html
···
<div class="flex justify-between pb-5">
<select
onchange="window.location.href = '/{{ .RepoInfo.FullName }}/tree/' + encodeURIComponent(this.value)"
-
class="p-1 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
+
class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
>
-
<optgroup label="branches" class="bold text-sm">
+
<optgroup label="branches ({{len .Branches}})" class="bold text-sm">
{{ range .Branches }}
<option
value="{{ .Reference.Name }}"
···
</option>
{{ end }}
</optgroup>
-
<optgroup label="tags" class="bold text-sm">
+
<optgroup label="tags ({{len .Tags}})" class="bold text-sm">
{{ range .Tags }}
<option
value="{{ .Reference.Name }}"
···
{{ define "rightInfo" }}
<div id="right-info" class="col-span-1">
-
<div id="commit-log" class="md:col-span-1">
-
<h2
-
class="flex text-gray-500 dark:text-gray-400 items-center gap-2 pb-4 pl-2"
-
>
-
{{ i "logs" "w-4 h-4" }}
-
commits
-
</h2>
-
{{ range .CommitsTrunc }}
-
<div class="relative px-2 pb-8">
-
<div id="commit-message">
-
{{ $messageParts := splitN .Message "\n\n" 2 }}
-
<div class="text-base cursor-pointer">
-
<div>
-
<div>
-
<a
-
href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash.String }}"
-
class="inline no-underline hover:underline dark:text-white"
-
>{{ index $messageParts 0 }}</a
-
>
-
{{ if gt (len $messageParts) 1 }}
+
{{ block "commitLog" . }} {{ end }}
+
{{ block "branchList" . }} {{ end }}
+
{{ block "tagList" . }} {{ end }}
+
</div>
+
{{ end }}
+
+
{{ define "commitLog" }}
+
<div id="commit-log" class="md:col-span-1 px-2 pb-4">
+
<div class="flex justify-between items-center">
+
<a href="/{{ .RepoInfo.FullName }}/commits/{{ .Ref | urlquery }}" class="flex text-black dark:text-white items-center gap-4 pb-2 no-underline hover:no-underline group">
+
<div class="flex gap-2 items-center">
+
{{ i "git-commit-horizontal" "w-4 h-4" }} commits
+
</div>
+
{{ if lt (len .CommitsTrunc) .TotalCommits }}
+
<span class="hidden group-hover:flex gap-2 items-center text-sm text-gray-500 dark:text-gray-400 ">
+
view {{ .TotalCommits }} commits {{ i "chevron-right" "w-4 h-4" }}
+
</span>
+
{{ end }}
+
</a>
+
</div>
+
<div class="flex flex-col gap-6">
+
{{ range .CommitsTrunc }}
+
<div>
+
<div id="commit-message">
+
{{ $messageParts := splitN .Message "\n\n" 2 }}
+
<div class="text-base cursor-pointer">
+
<div>
+
<div>
+
<a
+
href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash.String }}"
+
class="inline no-underline hover:underline dark:text-white"
+
>{{ index $messageParts 0 }}</a
+
>
+
{{ if gt (len $messageParts) 1 }}
+
+
<button
+
class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded dark:bg-gray-700 dark:hover:bg-gray-600"
+
hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')"
+
>
+
{{ i "ellipsis" "w-3 h-3" }}
+
</button>
+
{{ end }}
+
</div>
+
{{ if gt (len $messageParts) 1 }}
+
<p
+
class="hidden mt-1 text-sm cursor-text pb-2 dark:text-gray-300"
+
>
+
{{ nl2br (index $messageParts 1) }}
+
</p>
+
{{ end }}
+
</div>
+
</div>
+
</div>
+
+
<div class="text-xs text-gray-500 dark:text-gray-400">
+
<span class="font-mono">
+
<a
+
href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash.String }}"
+
class="text-gray-500 dark:text-gray-400 no-underline hover:underline"
+
>{{ slice .Hash.String 0 8 }}</a
+
></span
+
>
+
<span
+
class="mx-2 before:content-['·'] before:select-none"
+
></span>
+
<span>
+
{{ $didOrHandle := index $.EmailToDidOrHandle .Author.Email }}
+
<a
+
href="{{ if $didOrHandle }}
+
/{{ $didOrHandle }}
+
{{ else }}
+
mailto:{{ .Author.Email }}
+
{{ end }}"
+
class="text-gray-500 dark:text-gray-400 no-underline hover:underline"
+
>{{ if $didOrHandle }}
+
{{ $didOrHandle }}
+
{{ else }}
+
{{ .Author.Name }}
+
{{ end }}</a
+
>
+
</span>
+
<div
+
class="inline-block px-1 select-none after:content-['·']"
+
></div>
+
<span>{{ timeFmt .Author.When }}</span>
+
{{ $tagsForCommit := index $.TagMap .Hash.String }}
+
{{ if gt (len $tagsForCommit) 0 }}
+
<div
+
class="inline-block px-1 select-none after:content-['·']"
+
></div>
+
{{ end }}
+
{{ range $tagsForCommit }}
+
<span
+
class="text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 mx-1/2 inline-flex items-center"
+
>
+
{{ . }}
+
</span>
+
{{ end }}
+
</div>
+
</div>
+
{{ end }}
+
</div>
+
</div>
+
{{ end }}
-
<button
-
class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded dark:bg-gray-700 dark:hover:bg-gray-600"
-
hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')"
-
>
-
{{ i "ellipsis" "w-3 h-3" }}
-
</button>
-
{{ end }}
-
</div>
-
{{ if gt (len $messageParts) 1 }}
-
<p
-
class="hidden mt-1 text-sm cursor-text pb-2 dark:text-gray-300"
-
>
-
{{ nl2br (index $messageParts 1) }}
-
</p>
-
{{ end }}
-
</div>
-
</div>
-
</div>
+
{{ define "branchList" }}
+
{{ if gt (len .BranchesTrunc) 0 }}
+
<div id="branches" class="md:col-span-1 px-2 py-4 border-t border-gray-200 dark:border-gray-700">
+
<a href="/{{ .RepoInfo.FullName }}/branches" class="flex text-black dark:text-white items-center gap-4 pb-2 no-underline hover:no-underline group">
+
<div class="flex gap-2 items-center">
+
<!-- git-branch icon is seemingly bigger than others at 4x4 -->
+
{{ i "git-branch" "w-3 h-3" }} branches
+
</div>
+
{{ if lt (len .BranchesTrunc) (len .Branches) }}
+
<span class="hidden group-hover:flex gap-2 items-center text-sm text-gray-500 dark:text-gray-400 ">
+
view {{ len .Branches }} branches {{ i "chevron-right" "w-4 h-4" }}
+
</span>
+
{{ end }}
+
</a>
+
<div class="flex flex-col gap-1">
+
{{ range .BranchesTrunc }}
+
<div class="text-base flex items-center gap-2">
+
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ .Reference.Name | urlquery }}"
+
class="inline no-underline hover:underline dark:text-white">
+
{{ .Reference.Name }}
+
</a>
+
{{ if .Commit }}
+
<span class="px-1 text-gray-500 dark:text-gray-400 select-none after:content-['·']"></span>
+
<time class="text-xs text-gray-500 dark:text-gray-400">{{ timeFmt .Commit.Author.When }}</time>
+
{{ end }}
+
{{ if .IsDefault }}
+
<span class="px-1 text-gray-500 dark:text-gray-400 select-none after:content-['·']"></span>
+
<span class="bg-gray-200 dark:bg-gray-700 rounded py-1/2 px-1 text-xs font-mono">default</span>
+
{{ end }}
+
</div>
+
{{ end }}
+
</div>
+
</div>
+
{{ end }}
+
{{ end }}
-
<div class="text-xs text-gray-500 dark:text-gray-400">
-
<span class="font-mono">
-
<a
-
href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash.String }}"
-
class="text-gray-500 dark:text-gray-400 no-underline hover:underline"
-
>{{ slice .Hash.String 0 8 }}</a
-
></span
-
>
-
<span
-
class="mx-2 before:content-['·'] before:select-none"
-
></span>
-
<span>
-
{{ $didOrHandle := index $.EmailToDidOrHandle .Author.Email }}
-
<a
-
href="{{ if $didOrHandle }}
-
/{{ $didOrHandle }}
-
{{ else }}
-
mailto:{{ .Author.Email }}
-
{{ end }}"
-
class="text-gray-500 dark:text-gray-400 no-underline hover:underline"
-
>{{ if $didOrHandle }}
-
{{ $didOrHandle }}
-
{{ else }}
-
{{ .Author.Name }}
-
{{ end }}</a
-
>
-
</span>
-
<div
-
class="inline-block px-1 select-none after:content-['·']"
-
></div>
-
<span>{{ timeFmt .Author.When }}</span>
-
{{ $tagsForCommit := index $.TagMap .Hash.String }}
-
{{ if gt (len $tagsForCommit) 0 }}
-
<div
-
class="inline-block px-1 select-none after:content-['·']"
-
></div>
-
{{ end }}
-
{{ range $tagsForCommit }}
-
<span
-
class="text-xs rounded bg-gray-100 dark:bg-gray-700 text-black dark:text-white font-mono px-2 mx-1/2 inline-flex items-center"
-
>
-
{{ . }}
-
</span>
-
{{ end }}
-
</div>
-
</div>
+
{{ define "tagList" }}
+
{{ if gt (len .TagsTrunc) 0 }}
+
<div id="tags" class="md:col-span-1 px-2 py-4 border-t border-gray-200 dark:border-gray-700">
+
<div class="flex justify-between items-center">
+
<a href="/{{ .RepoInfo.FullName }}/tags" class="flex text-black dark:text-white items-center gap-4 pb-2 no-underline hover:no-underline group">
+
<div class="flex gap-2 items-center">
+
{{ i "tags" "w-4 h-4" }} tags
+
</div>
+
{{ if lt (len .TagsTrunc) (len .Tags) }}
+
<span class="hidden group-hover:flex gap-2 items-center text-sm text-gray-500 dark:text-gray-400 ">
+
view {{ len .Tags }} tags {{ i "chevron-right" "w-4 h-4" }}
+
</span>
+
{{ end }}
+
</a>
+
</div>
+
<div class="flex flex-col gap-1">
+
{{ range $idx, $tag := .TagsTrunc }}
+
{{ with $tag }}
+
<div>
+
<div class="text-base flex items-center gap-2">
+
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ .Reference.Name | urlquery }}"
+
class="inline no-underline hover:underline dark:text-white">
+
{{ .Reference.Name }}
+
</a>
+
</div>
+
<div>
+
{{ with .Tag }}
+
<time class="text-xs text-gray-500 dark:text-gray-400">{{ timeFmt .Tagger.When }}</time>
{{ end }}
-
{{ $more := sub .TotalCommits (len .CommitsTrunc) }}
-
{{ if gt $more 0 }}
-
<div
-
class="flex text-gray-500 dark:text-gray-400 mb-2 gap-1 justify-end items-center"
-
>
-
<a
-
href="/{{ .RepoInfo.FullName }}/commits/{{ .Ref | urlquery }}"
-
class="text-gray-500 dark:text-gray-400 text-sm"
-
>
-
&hellip; and {{ $more }} more
-
</a>
-
{{ i "arrow-right" "w-3 h-3" }}
-
</div>
+
{{ if eq $idx 0 }}
+
<span class="px-1 text-gray-500 dark:text-gray-400 select-none after:content-['·']"></span>
+
<span class="bg-gray-200 dark:bg-gray-700 rounded py-1/2 px-1 text-xs font-mono">latest</span>
{{ end }}
+
</div>
</div>
-
{{ if gt (len .Tags) 0 }}
-
<div
-
id="tags"
-
class="md:col-span-1 pt-4 border-t border-gray-200 dark:border-gray-700"
-
>
-
<h2
-
class="flex text-gray-500 dark:text-gray-400 items-center gap-2 pb-4 pl-2"
-
>
-
{{ i "tags" "w-4 h-4" }}
-
tags
-
</h2>
-
{{ range .Tags }}
-
<div class="relative px-2 pb-4">
-
<div class="text-base">
-
<div>
-
<a
-
href="/{{ $.RepoInfo.FullName }}/tree/{{ .Reference.Name | urlquery }}"
-
class="inline no-underline hover:underline dark:text-white"
-
>{{ .Reference.Name }}</a
-
>
-
{{ if gt (len .Message) 0 }}
-
{{ $messageParts := splitN .Message "\n\n" 2 }}
-
{{ $title := index $messageParts 0 }}
-
{{ $description := index $messageParts 1 }}
-
<span
-
class="text-sm text-gray-500 dark:text-gray-400 ml-2 truncate inline-block align-middle"
-
>{{ $title }}</span
-
>
-
{{ if gt (len $description) 1 }}
-
<button
-
class="py-1/2 px-1 bg-gray-200 hover:bg-gray-400 rounded dark:bg-gray-700 dark:hover:bg-gray-600"
-
hx-on:click="this.parentElement.nextElementSibling.classList.toggle('hidden')"
-
>
-
{{ i "ellipsis" "w-3 h-3" }}
-
</button>
-
{{ end }}
-
{{ end }}
-
</div>
-
{{ if gt (len .Message) 0 }}
-
{{ $messageParts := splitN .Message "\n\n" 2 }}
-
{{ $description := index $messageParts 1 }}
-
{{ if gt (len $description) 1 }}
-
<div
-
class="hidden mt-1 text-sm cursor-text pb-2 dark:text-gray-300"
-
>
-
{{ $description | markdown }}
-
</div>
-
{{ end }}
-
{{ end }}
-
<div
-
class="text-xs text-gray-500 dark:text-gray-400"
-
>
-
<span class="font-mono">
-
<a
-
href="/{{ $.RepoInfo.FullName }}/commit/{{ .Reference.Hash }}"
-
class="text-gray-500 dark:text-gray-400 no-underline hover:underline"
-
>{{ slice .Reference.Hash 0 8 }}</a
-
>
-
</span>
-
{{ with .Tag }}
-
<div
-
class="inline-block px-1 select-none after:content-['·']"
-
></div>
-
<time>{{ timeFmt .Tagger.When }}</time>
-
{{ end }}
-
</div>
-
</div>
-
</div>
-
{{ end }}
-
</div>
+
{{ end }}
{{ end }}
+
</div>
</div>
+
{{ end }}
{{ end }}
{{ define "repoAfter" }}
{{- if .HTMLReadme }}
-
<div
-
class="mt-4 bg-white text-gray-600 dark:text-gray-400
-
px-6 py-3 prose dark:prose-invert
-
border-gray-200 dark:border-gray-700
-
text-sm border-b rounded-tl rounded-tr"
-
>
-
{{ .ReadmeFileName }}
-
</div>
<section
-
class="p-6 rounded-br rounded-bl bg-white dark:bg-gray-800 dark:text-white w-full mx-auto overflow-auto {{ if not .Raw }}
+
class="p-6 mt-4 rounded-br rounded-bl bg-white dark:bg-gray-800 dark:text-white w-full mx-auto overflow-auto {{ if not .Raw }}
prose dark:prose-invert dark:[&_pre]:bg-gray-900
dark:[&_code]:text-gray-300 dark:[&_pre_code]:bg-gray-900
dark:[&_pre]:border dark:[&_pre]:border-gray-700
+43 -13
appview/pages/templates/repo/tags.html
···
+
{{ define "title" }}
+
tags · {{ .RepoInfo.FullName }}
+
{{ end }}
+
{{ define "repoContent" }}
-
{{ $name := .RepoInfo.Name }}
-
<h3>tags</h3>
-
<div class="refs">
-
{{ range .Tags }}
-
<div>
-
<strong>{{ .Ref.Name }}</strong>
-
<a href="/{{ $name }}/tree/{{ .Ref.Name }}/">browse</a>
-
<a href="/{{ $name }}/log/{{ .Ref.Name }}">log</a>
-
<a href="/{{ $name }}/archive/{{ .Ref.Name }}.tar.gz">tar.gz</a>
-
{{ if .Message }}
-
<pre>{{ .Message }}</pre>
+
<section>
+
<div class="flex flex-col py-2">
+
{{ range .Tags }}
+
<div class="grid grid-cols-12 items-start">
+
<!-- Header column (left) -->
+
<div class="col-span-3 border-r border-gray-200 dark:border-gray-700 h-full text-right px-2 pb-6">
+
<a href="/{{ $.RepoInfo.FullName }}/tree/{{ .Name | urlquery }}" class="no-underline hover:underline flex items-center justify-end gap-2 font-bold">
+
{{ i "tag" "w-4 h-4" }}
+
{{ .Name }}
+
</a>
+
<div class="flex flex-grow flex-col text-gray-500 dark:text-gray-400 text-sm">
+
{{ if .Tag }}
+
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ .Tag.Target.String }}"
+
class="no-underline hover:underline text-gray-500 dark:text-gray-400 flex items-center justify-end gap-2">
+
{{ i "git-commit-horizontal" "w-4 h-4" }}
+
{{ slice .Tag.Target.String 0 8 }}
+
</a>
+
<span>{{ .Tag.Tagger.Name }}</span>
+
<time>{{ timeFmt .Tag.Tagger.When }}</time>
+
{{ end }}
+
</div>
+
</div>
+
+
<!-- Paragraph column (right) -->
+
<div class="col-span-9 px-2 pb-6">
+
<div>
+
{{ if .Tag }}
+
{{ $messageParts := splitN .Tag.Message "\n\n" 2 }}
+
<p class="font-bold">{{ index $messageParts 0 }}</p>
+
{{ if gt (len $messageParts) 1 }}
+
<p class="cursor-text pb-2 text-sm">{{ nl2br (index $messageParts 1) }}</p>
{{ end }}
-
</div>
-
{{ end }}
+
{{ else }}
+
<p class="italic text-gray-500 dark:text-gray-400">no message</p>
+
{{ end }}
+
</div>
+
</div>
+
</div>
+
{{ end }}
</div>
+
</section>
{{ end }}
+54 -17
appview/state/repo.go
···
tagMap[hash] = append(tagMap[hash], branch.Name)
}
-
c, t := balanceTagsAndCommits(len(result.Commits), len(result.Tags), 10)
-
commits := result.Commits[:c]
-
tags := result.Tags[:t]
-
emails := uniqueEmails(commits)
+
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
+
if a.Name == result.Ref {
+
return -1
+
}
+
if a.IsDefault {
+
return -1
+
}
+
if a.Commit != nil {
+
if a.Commit.Author.When.Before(b.Commit.Author.When) {
+
return 1
+
} else {
+
return -1
+
}
+
}
+
return strings.Compare(a.Name, b.Name) * -1
+
})
-
for _, tag := range tags {
-
fmt.Printf("%#v\n\n", tag)
-
}
+
commitCount := len(result.Commits)
+
branchCount := len(result.Branches)
+
tagCount := len(result.Tags)
+
fileCount := len(result.Files)
+
+
commitCount, branchCount, tagCount = balanceIndexItems(commitCount, branchCount, tagCount, fileCount)
+
commitsTrunc := result.Commits[:min(commitCount, len(result.Commits))]
+
tagsTrunc := result.Tags[:min(tagCount, len(result.Tags))]
+
branchesTrunc := result.Branches[:min(branchCount, len(result.Branches))]
+
+
emails := uniqueEmails(commitsTrunc)
user := s.auth.GetUser(r)
s.pages.RepoIndexPage(w, pages.RepoIndexParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
TagMap: tagMap,
-
Tags: tags,
RepoIndexResponse: result,
-
CommitsTrunc: commits,
+
CommitsTrunc: commitsTrunc,
+
TagsTrunc: tagsTrunc,
+
BranchesTrunc: branchesTrunc,
EmailToDidOrHandle: EmailToDidOrHandle(s, emails),
})
return
···
ref := chi.URLParam(r, "ref")
-
protocol := "http"
-
if !s.config.Dev {
-
protocol = "https"
+
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+
if err != nil {
+
log.Println("failed to create unsigned client", err)
+
return
}
-
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/log/%s?page=%d&per_page=60", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, page))
+
resp, err := us.Log(f.OwnerDid(), f.RepoName, ref, page)
if err != nil {
log.Println("failed to reach knotserver", err)
return
···
return
}
-
protocol := "http"
-
if !s.config.Dev {
-
protocol = "https"
+
us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+
if err != nil {
+
log.Println("failed to create unsigned client", err)
+
return
}
-
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tags", protocol, f.Knot, f.OwnerDid(), f.RepoName))
+
resp, err := us.Tags(f.OwnerDid(), f.RepoName)
if err != nil {
log.Println("failed to reach knotserver", err)
return
···
log.Println("failed to parse response:", err)
return
}
+
+
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
+
if a.IsDefault {
+
return -1
+
}
+
if a.Commit != nil {
+
if a.Commit.Author.When.Before(b.Commit.Author.When) {
+
return 1
+
} else {
+
return -1
+
}
+
}
+
return strings.Compare(a.Name, b.Name) * -1
+
})
user := s.auth.GetUser(r)
s.pages.RepoBranches(w, pages.RepoBranchesParams{
+17 -17
appview/state/repo_util.go
···
return uniqueEmails
}
-
func balanceTagsAndCommits(commits, tags, totalDesired int) (int, int) {
-
if commits == 0 && tags == 0 {
-
return 0, 0
+
func balanceIndexItems(commitCount, branchCount, tagCount, fileCount int) (commitsTrunc int, branchesTrunc int, tagsTrunc int) {
+
if commitCount == 0 && tagCount == 0 && branchCount == 0 {
+
return
}
-
half := totalDesired / 2
+
// typically 1 item on right side = 2 files in height
+
availableSpace := fileCount / 2
-
if commits+tags <= totalDesired {
-
return commits, tags
-
}
-
-
if commits >= half && tags >= half {
-
return half, half
+
// clamp tagcount
+
if tagCount > 0 {
+
tagsTrunc = 1
+
availableSpace -= 1 // an extra subtracted for headers etc.
}
-
if commits < half {
-
return commits, min(tags, totalDesired-commits)
+
// clamp branchcount
+
if branchCount > 0 {
+
branchesTrunc = min(max(branchCount, 1), 2)
+
availableSpace -= branchesTrunc // an extra subtracted for headers etc.
}
-
if tags < half {
-
return min(commits, totalDesired-tags), tags
+
// show
+
if commitCount > 0 {
+
commitsTrunc = max(availableSpace, 3)
}
-
c := min(commits, half)
-
t := min(tags, totalDesired-c)
-
return c, t
+
return
}
func EmailToDidOrHandle(s *State, emails []string) map[string]string {
+50 -8
appview/state/signer.go
···
"log"
"net/http"
"net/url"
+
"strconv"
"time"
"tangled.sh/tangled.sh/core/types"
···
return unsignedClient, nil
}
-
func (us *UnsignedClient) newRequest(method, endpoint string, body []byte) (*http.Request, error) {
-
return http.NewRequest(method, us.Url.JoinPath(endpoint).String(), bytes.NewReader(body))
+
func (us *UnsignedClient) newRequest(method, endpoint string, query url.Values, body []byte) (*http.Request, error) {
+
reqUrl := us.Url.JoinPath(endpoint)
+
+
// add query parameters
+
if query != nil {
+
reqUrl.RawQuery = query.Encode()
+
}
+
+
return http.NewRequest(method, reqUrl.String(), bytes.NewReader(body))
}
func (us *UnsignedClient) Index(ownerDid, repoName, ref string) (*http.Response, error) {
···
endpoint = fmt.Sprintf("/%s/%s", ownerDid, repoName)
}
-
req, err := us.newRequest(Method, endpoint, nil)
+
req, err := us.newRequest(Method, endpoint, nil, nil)
+
if err != nil {
+
return nil, err
+
}
+
+
return us.client.Do(req)
+
}
+
+
func (us *UnsignedClient) Log(ownerDid, repoName, ref string, page int) (*http.Response, error) {
+
const (
+
Method = "GET"
+
)
+
+
endpoint := fmt.Sprintf("/%s/%s/log/%s", ownerDid, repoName, url.PathEscape(ref))
+
+
query := url.Values{}
+
query.Add("page", strconv.Itoa(page))
+
query.Add("per_page", strconv.Itoa(60))
+
+
req, err := us.newRequest(Method, endpoint, query, nil)
if err != nil {
return nil, err
}
···
endpoint := fmt.Sprintf("/%s/%s/branches", ownerDid, repoName)
-
req, err := us.newRequest(Method, endpoint, nil)
+
req, err := us.newRequest(Method, endpoint, nil, nil)
+
if err != nil {
+
return nil, err
+
}
+
+
return us.client.Do(req)
+
}
+
+
func (us *UnsignedClient) Tags(ownerDid, repoName string) (*http.Response, error) {
+
const (
+
Method = "GET"
+
)
+
+
endpoint := fmt.Sprintf("/%s/%s/tags", ownerDid, repoName)
+
+
req, err := us.newRequest(Method, endpoint, nil, nil)
if err != nil {
return nil, err
}
···
endpoint := fmt.Sprintf("/%s/%s/branches/%s", ownerDid, repoName, url.PathEscape(branch))
-
req, err := us.newRequest(Method, endpoint, nil)
+
req, err := us.newRequest(Method, endpoint, nil, nil)
if err != nil {
return nil, err
}
···
endpoint := fmt.Sprintf("/%s/%s/branches/default", ownerDid, repoName)
-
req, err := us.newRequest(Method, endpoint, nil)
+
req, err := us.newRequest(Method, endpoint, nil, nil)
if err != nil {
return nil, err
}
···
Endpoint = "/capabilities"
)
-
req, err := us.newRequest(Method, Endpoint, nil)
+
req, err := us.newRequest(Method, Endpoint, nil, nil)
if err != nil {
return nil, err
}
···
endpoint := fmt.Sprintf("/%s/%s/compare/%s/%s", ownerDid, repoName, url.PathEscape(rev1), url.PathEscape(rev2))
-
req, err := us.newRequest(Method, endpoint, nil)
+
req, err := us.newRequest(Method, endpoint, nil, nil)
if err != nil {
return nil, fmt.Errorf("Failed to create request.")
}
+27 -3
knotserver/git/git.go
···
return commits, nil
}
+
func (g *GitRepo) Commit(h plumbing.Hash) (*object.Commit, error) {
+
return g.r.CommitObject(h)
+
}
+
func (g *GitRepo) LastCommit() (*object.Commit, error) {
c, err := g.r.CommitObject(g.h)
if err != nil {
···
return tags, nil
}
-
func (g *GitRepo) Branches() ([]*plumbing.Reference, error) {
+
func (g *GitRepo) Branches() ([]types.Branch, error) {
bi, err := g.r.Branches()
if err != nil {
return nil, fmt.Errorf("branchs: %w", err)
}
-
branches := []*plumbing.Reference{}
+
branches := []types.Branch{}
+
+
defaultBranch, err := g.FindMainBranch()
+
if err != nil {
+
return nil, fmt.Errorf("getting default branch", "error", err.Error())
+
}
_ = bi.ForEach(func(ref *plumbing.Reference) error {
-
branches = append(branches, ref)
+
b := types.Branch{}
+
b.Hash = ref.Hash().String()
+
b.Name = ref.Name().Short()
+
+
// resolve commit that this branch points to
+
commit, _ := g.Commit(ref.Hash())
+
if commit != nil {
+
b.Commit = commit
+
}
+
+
if defaultBranch != "" && defaultBranch == b.Name {
+
b.IsDefault = true
+
}
+
+
branches = append(branches, b)
+
return nil
})
+23 -19
knotserver/routes.go
···
return
}
-
bs := []types.Branch{}
-
for _, branch := range branches {
-
b := types.Branch{}
-
b.Hash = branch.Hash().String()
-
b.Name = branch.Name().Short()
-
bs = append(bs, b)
-
}
-
tags, err := gr.Tags()
if err != nil {
// Non-fatal, we *should* have at least one branch to show.
···
Readme: readmeContent,
ReadmeFileName: readmeFile,
Files: files,
-
Branches: bs,
+
Branches: branches,
Tags: rtags,
TotalCommits: total,
}
···
func (h *Handle) Log(w http.ResponseWriter, r *http.Request) {
ref := chi.URLParam(r, "ref")
+
ref, _ = url.PathUnescape(ref)
+
path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r))
l := h.l.With("handler", "Log", "ref", ref, "path", path)
···
return
}
-
bs := []types.Branch{}
-
for _, branch := range branches {
-
b := types.Branch{}
-
b.Hash = branch.Hash().String()
-
b.Name = branch.Name().Short()
-
bs = append(bs, b)
-
}
-
resp := types.RepoBranchesResponse{
-
Branches: bs,
+
Branches: branches,
}
writeJSON(w, resp)
···
ref, err := gr.Branch(branchName)
if err != nil {
-
l.Error("getting branches", "error", err.Error())
+
l.Error("getting branch", "error", err.Error())
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
+
commit, err := gr.Commit(ref.Hash())
+
if err != nil {
+
l.Error("getting commit object", "error", err.Error())
+
writeError(w, err.Error(), http.StatusInternalServerError)
+
return
+
}
+
+
defaultBranch, err := gr.FindMainBranch()
+
isDefault := false
+
if err != nil {
+
l.Error("getting default branch", "error", err.Error())
+
// do not quit though
+
} else if defaultBranch == branchName {
+
isDefault = true
+
}
+
resp := types.RepoBranchResponse{
Branch: types.Branch{
Reference: types.Reference{
Name: ref.Name().Short(),
Hash: ref.Hash().String(),
},
+
Commit: commit,
+
IsDefault: isDefault,
},
}
+2
types/repo.go
···
type Branch struct {
Reference `json:"reference"`
+
Commit *object.Commit `json:"commit,omitempty"`
+
IsDefault bool `json:"is_deafult,omitempty"`
}
type RepoTagsResponse struct {