Monorepo for Tangled tangled.org

add nicediff view to pulls

Changed files
+175 -110
appview
db
pages
templates
fragments
repo
+44
appview/db/pulls.go
··· 3 3 import ( 4 4 "database/sql" 5 5 "fmt" 6 + "log" 6 7 "strings" 7 8 "time" 8 9 10 + "github.com/bluekeyes/go-gitdiff/gitdiff" 9 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 + "github.com/sotangled/tangled/types" 10 13 ) 11 14 12 15 type PullState int ··· 100 103 func (p *Pull) LatestPatch() string { 101 104 latestSubmission := p.Submissions[len(p.Submissions)-1] 102 105 return latestSubmission.Patch 106 + } 107 + 108 + func (s PullSubmission) AsNiceDiff(targetBranch string) types.NiceDiff { 109 + patch := s.Patch 110 + 111 + diffs, _, err := gitdiff.Parse(strings.NewReader(patch)) 112 + if err != nil { 113 + log.Println(err) 114 + } 115 + 116 + nd := types.NiceDiff{} 117 + nd.Commit.Parent = targetBranch 118 + 119 + for _, d := range diffs { 120 + ndiff := types.Diff{} 121 + ndiff.Name.New = d.NewName 122 + ndiff.Name.Old = d.OldName 123 + ndiff.IsBinary = d.IsBinary 124 + ndiff.IsNew = d.IsNew 125 + ndiff.IsDelete = d.IsDelete 126 + ndiff.IsCopy = d.IsCopy 127 + ndiff.IsRename = d.IsRename 128 + 129 + for _, tf := range d.TextFragments { 130 + ndiff.TextFragments = append(ndiff.TextFragments, *tf) 131 + for _, l := range tf.Lines { 132 + switch l.Op { 133 + case gitdiff.OpAdd: 134 + nd.Stat.Insertions += 1 135 + case gitdiff.OpDelete: 136 + nd.Stat.Deletions += 1 137 + } 138 + } 139 + } 140 + 141 + nd.Diff = append(nd.Diff, ndiff) 142 + } 143 + 144 + nd.Stat.FilesChanged = len(diffs) 145 + 146 + return nd 103 147 } 104 148 105 149 func NewPull(tx *sql.Tx, pull *Pull) error {
+112
appview/pages/templates/fragments/diff.html
··· 1 + {{ define "fragments/diff" }} 2 + {{ $repo := index . 0 }} 3 + {{ $diff := index . 1 }} 4 + {{ $commit := $diff.Commit }} 5 + {{ $stat := $diff.Stat }} 6 + {{ $diff := $diff.Diff }} 7 + 8 + {{ $this := $commit.This }} 9 + {{ $parent := $commit.Parent }} 10 + 11 + {{ $last := sub (len $diff) 1 }} 12 + {{ range $idx, $hunk := $diff }} 13 + {{ with $hunk }} 14 + <section class="mt-6 border border-gray-200 w-full mx-auto rounded bg-white drop-shadow-sm"> 15 + <div id="file-{{ .Name.New }}"> 16 + <div id="diff-file"> 17 + <details open> 18 + <summary class="list-none cursor-pointer sticky top-0"> 19 + <div id="diff-file-header" class="rounded cursor-pointer bg-white flex justify-between"> 20 + <div id="left-side-items" class="p-2 flex gap-2 items-center"> 21 + {{ $markerstyle := "diff-type p-1 mr-1 font-mono text-sm rounded select-none" }} 22 + 23 + {{ if .IsNew }} 24 + <span class="bg-green-100 text-green-700 {{ $markerstyle }}">ADDED</span> 25 + {{ else if .IsDelete }} 26 + <span class="bg-red-100 text-red-700 {{ $markerstyle }}">DELETED</span> 27 + {{ else if .IsCopy }} 28 + <span class="bg-gray-100 text-gray-700 {{ $markerstyle }}">COPIED</span> 29 + {{ else if .IsRename }} 30 + <span class="bg-gray-100 text-gray-700 {{ $markerstyle }}">RENAMED</span> 31 + {{ else }} 32 + <span class="bg-gray-100 text-gray-700 {{ $markerstyle }}">MODIFIED</span> 33 + {{ end }} 34 + 35 + {{ if .IsDelete }} 36 + <a {{if $this }}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.Old }}"{{end}}> 37 + {{ .Name.Old }} 38 + </a> 39 + {{ else if (or .IsCopy .IsRename) }} 40 + <a {{if $parent}}href="/{{ $repo }}/blob/{{ $parent }}/{{ .Name.Old }}"{{end}}> 41 + {{ .Name.Old }} 42 + </a> 43 + <i class="w-4 h-4" data-lucide="arrow-right"></i> 44 + <a {{if $this}}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.New }}"{{end}}> 45 + {{ .Name.New }} 46 + </a> 47 + {{ else }} 48 + <a {{if $this}}href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.New }}"{{end}}> 49 + {{ .Name.New }} 50 + </a> 51 + {{ end }} 52 + </div> 53 + 54 + {{ $iconstyle := "p-1 mx-1 hover:bg-gray-100 rounded" }} 55 + <div id="right-side-items" class="p-2 flex items-center"> 56 + <a title="top of file" href="#file-{{ .Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-up-to-line"></i></a> 57 + {{ if gt $idx 0 }} 58 + {{ $prev := index $diff (sub $idx 1) }} 59 + <a title="previous file" href="#file-{{ $prev.Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-up"></i></a> 60 + {{ end }} 61 + 62 + {{ if lt $idx $last }} 63 + {{ $next := index $diff (add $idx 1) }} 64 + <a title="next file" href="#file-{{ $next.Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-down"></i></a> 65 + {{ end }} 66 + </div> 67 + 68 + </div> 69 + </summary> 70 + 71 + <div class="transition-all duration-700 ease-in-out"> 72 + {{ if .IsDelete }} 73 + <p class="text-center text-gray-400 p-4"> 74 + This file has been deleted in this commit. 75 + </p> 76 + {{ else }} 77 + {{ if .IsBinary }} 78 + <p class="text-center text-gray-400 p-4"> 79 + This is a binary file and will not be displayed. 80 + </p> 81 + {{ else }} 82 + <pre class="overflow-auto"> 83 + {{- range .TextFragments -}} 84 + <div class="bg-gray-100 text-gray-500 select-none">{{ .Header }}</div> 85 + {{- range .Lines -}} 86 + {{- if eq .Op.String "+" -}} 87 + <div class="bg-green-100 text-green-700 p-1"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div> 88 + {{- end -}} 89 + 90 + {{- if eq .Op.String "-" -}} 91 + <div class="bg-red-100 text-red-700 p-1"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div> 92 + {{- end -}} 93 + 94 + {{- if eq .Op.String " " -}} 95 + <div class="bg-white text-gray-500 px"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div> 96 + {{- end -}} 97 + 98 + {{- end -}} 99 + {{- end -}} 100 + </pre> 101 + {{- end -}} 102 + {{ end }} 103 + </div> 104 + 105 + </details> 106 + 107 + </div> 108 + </div> 109 + </section> 110 + {{ end }} 111 + {{ end }} 112 + {{ end }}
+1 -103
appview/pages/templates/repo/commit.html
··· 55 55 {{end}} 56 56 57 57 {{ define "repoAfter" }} 58 - 59 - {{ $repo := .RepoInfo.FullName }} 60 - {{ $commit := .Diff.Commit }} 61 - {{ $stat := .Diff.Stat }} 62 - {{ $diff := .Diff.Diff }} 63 - 64 - {{ $this := $commit.This }} 65 - {{ $parent := $commit.Parent }} 66 - 67 - {{ $last := sub (len $diff) 1 }} 68 - {{ range $idx, $hunk := $diff }} 69 - {{ with $hunk }} 70 - <section class="mt-6 border border-gray-200 w-full mx-auto rounded bg-white drop-shadow-sm"> 71 - <div id="file-{{ .Name.New }}"> 72 - <div id="diff-file"> 73 - <details open> 74 - <summary class="list-none cursor-pointer sticky top-0"> 75 - <div id="diff-file-header" class="rounded cursor-pointer bg-white flex justify-between"> 76 - <div id="left-side-items" class="p-2 flex gap-2 items-center"> 77 - {{ $markerstyle := "diff-type p-1 mr-1 font-mono text-sm rounded select-none" }} 78 - 79 - {{ if .IsNew }} 80 - <span class="bg-green-100 text-green-700 {{ $markerstyle }}">ADDED</span> 81 - {{ else if .IsDelete }} 82 - <span class="bg-red-100 text-red-700 {{ $markerstyle }}">DELETED</span> 83 - {{ else if .IsCopy }} 84 - <span class="bg-gray-100 text-gray-700 {{ $markerstyle }}">COPIED</span> 85 - {{ else if .IsRename }} 86 - <span class="bg-gray-100 text-gray-700 {{ $markerstyle }}">RENAMED</span> 87 - {{ else }} 88 - <span class="bg-gray-100 text-gray-700 {{ $markerstyle }}">MODIFIED</span> 89 - {{ end }} 90 - 91 - {{ if .IsDelete }} 92 - <a href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.Old }}">{{ .Name.Old }}</a> 93 - {{ else if (or .IsCopy .IsRename) }} 94 - <a href="/{{ $repo }}/blob/{{ $parent }}/{{ .Name.Old }}">{{ .Name.Old }}</a> 95 - <i class="w-4 h-4" data-lucide="arrow-right"></i> 96 - <a href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.New }}">{{ .Name.New }}</a> 97 - {{ else }} 98 - <a href="/{{ $repo }}/blob/{{ $this }}/{{ .Name.New }}">{{ .Name.New }}</a> 99 - {{ end }} 100 - </div> 101 - 102 - {{ $iconstyle := "p-1 mx-1 hover:bg-gray-100 rounded" }} 103 - <div id="right-side-items" class="p-2 flex items-center"> 104 - <a title="top of file" href="#file-{{ .Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-up-to-line"></i></a> 105 - {{ if gt $idx 0 }} 106 - {{ $prev := index $diff (sub $idx 1) }} 107 - <a title="previous file" href="#file-{{ $prev.Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-up"></i></a> 108 - {{ end }} 109 - 110 - {{ if lt $idx $last }} 111 - {{ $next := index $diff (add $idx 1) }} 112 - <a title="next file" href="#file-{{ $next.Name.New }}" class="{{ $iconstyle }}"><i class="w-4 h-4" data-lucide="arrow-down"></i></a> 113 - {{ end }} 114 - </div> 115 - 116 - </div> 117 - </summary> 118 - 119 - <div class="transition-all duration-700 ease-in-out"> 120 - {{ if .IsDelete }} 121 - <p class="text-center text-gray-400 p-4"> 122 - This file has been deleted in this commit. 123 - </p> 124 - {{ else }} 125 - {{ if .IsBinary }} 126 - <p class="text-center text-gray-400 p-4"> 127 - This is a binary file and will not be displayed. 128 - </p> 129 - {{ else }} 130 - <pre class="overflow-auto"> 131 - {{- range .TextFragments -}} 132 - <div class="bg-gray-100 text-gray-500 select-none">{{ .Header }}</div> 133 - {{- range .Lines -}} 134 - {{- if eq .Op.String "+" -}} 135 - <div class="bg-green-100 text-green-700 p-1"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div> 136 - {{- end -}} 137 - 138 - {{- if eq .Op.String "-" -}} 139 - <div class="bg-red-100 text-red-700 p-1"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div> 140 - {{- end -}} 141 - 142 - {{- if eq .Op.String " " -}} 143 - <div class="bg-white text-gray-500 px"><span class="select-none mx-2">{{ .Op.String }}</span><span>{{ .Line }}</span></div> 144 - {{- end -}} 145 - 146 - {{- end -}} 147 - {{- end -}} 148 - </pre> 149 - {{- end -}} 150 - {{ end }} 151 - </div> 152 - 153 - </details> 154 - 155 - </div> 156 - </div> 157 - </section> 158 - {{ end }} 159 - {{ end }} 160 - 58 + {{ template "fragments/diff" (list .RepoInfo.FullName .Diff) }} 161 59 {{end}}
+1 -1
appview/pages/templates/repo/index.html
··· 13 13 {{ define "branchSelector" }} 14 14 <div class="flex justify-between pb-5"> 15 15 <select 16 - onchange="window.location.href = '/{{ .RepoInfo.FullName }}/tree/' + this.value" 16 + onchange="window.location.href = '/{{ .RepoInfo.FullName }}/tree/' + encodeURIComponent(this.value)" 17 17 class="p-1 border border-gray-200 bg-white" 18 18 > 19 19 <optgroup label="branches" class="bold text-sm">
+6 -5
appview/pages/templates/repo/pulls/pull.html
··· 93 93 94 94 {{ define "submissions" }} 95 95 {{ $lastIdx := sub (len .Pull.Submissions) 1 }} 96 + {{ $targetBranch := .Pull.TargetBranch }} 97 + {{ $repoName := .RepoInfo.FullName }} 96 98 {{ range $idx, $item := .Pull.Submissions }} 99 + {{ $diff := $item.AsNiceDiff $targetBranch }} 97 100 {{ with $item }} 98 101 {{ $oneIndexedRound := add .RoundNumber 1 }} 99 102 <details {{ if eq $idx $lastIdx }}open{{ end }}> ··· 106 109 <span> 107 110 {{ $owner := index $.DidHandleMap $.Pull.OwnerDid }} 108 111 submitted by <a href="/{{ $owner }}">{{ $owner }}</a> 109 - <span class="before:content-['·']"></span> 110 - <a href="/{{ $.RepoInfo.FullName }}/pulls/{{ $.Pull.PullId }}/patch">view patch</a> 111 112 <span class="select-none before:content-['\00B7']"></span> 112 113 <time>{{ .Created | timeFmt }}</time> 113 114 <span class="select-none before:content-['·']"></span> ··· 121 122 </div> 122 123 </summary> 123 124 <div class="pl-12 flex flex-col gap-2 mt-2 relative"> 124 - <!--div class="bg-white rounded drop-shadow-sm p-4"> 125 - <pre class="overflow-auto"><code>{{- .Patch -}}</code></pre> 126 - </div--> 125 + <div> 126 + {{ template "fragments/diff" (list $repoName $diff) }} 127 + </div> 127 128 128 129 {{ range .Comments }} 129 130 <div id="comment-{{.ID}}" class="bg-white rounded drop-shadow-sm py-2 px-4 relative w-fit">
+11 -1
flake.nix
··· 313 313 314 314 environment.systemPackages = with pkgs; [git]; 315 315 316 + system.activationScripts.gitConfig = '' 317 + mkdir -p /home/git/.config/git 318 + cat > /home/git/.config/git/config << EOF 319 + [user] 320 + name = Git User 321 + email = git@example.com 322 + EOF 323 + chown -R git:git /home/git/.config 324 + ''; 325 + 316 326 users.users.git = { 317 327 isNormalUser = true; 318 328 home = "/home/git"; ··· 380 390 services.tangled-knotserver = { 381 391 enable = true; 382 392 server = { 383 - secret = "ad7b32ded52fbe96e09f469a288084ee01cd12c971da87a1cbb87ef67081bd87"; 393 + secret = "6995e040e80e2d593b5e5e9ca611a70140b9ef8044add0a28b48b1ee34aa3e85"; 384 394 hostname = "localhost:6000"; 385 395 listenAddr = "0.0.0.0:6000"; 386 396 };