repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

commit
d15bf3c
parent
affd3a6
author
jolheiser
date
2024-07-19 12:26:38 -0400 EDT
feat: consistent user display

This patch unifies how user accounts look across the entire frontend
It also adds some CSS specifically for reviews/admins

Signed-off-by: jolheiser <git@jolheiser.com>
9 files changed,  +97, -48
M web.go
A static/git-pr.css
+20, -0
 1@@ -0,0 +1,20 @@
 2+.pill-review {
 3+  border: 1px solid var(--review);
 4+  color: var(--review);
 5+}
 6+
 7+.box-sm-review {
 8+  border: 2px solid var(--review);
 9+  padding: 0.15rem 0.35rem;
10+}
11+
12+.box-review {
13+  border: 2px solid var(--review);
14+  padding: 0.5rem 0.75rem;
15+}
16+
17+.pill-admin {
18+  border: 1px solid var(--admin);
19+  color: var(--admin);
20+}
21+
M static/vars.css
+2, -0
1@@ -15,4 +15,6 @@
2   --grey: #414558;
3   --grey-light: #6a708e;
4   --shadow: #252525;
5+  --review: #f9e2af;
6+  --admin: #f38ba8;
7 }
M tmpl/base.html
+1, -0
1@@ -10,6 +10,7 @@
2     {{template "meta" .}}
3 
4     <link rel="stylesheet" href="/static/smol.css" />
5+    <link rel="stylesheet" href="/static/git-pr.css" />
6     <link rel="stylesheet" href="/static/vars.css" />
7     <link rel="stylesheet" href="/syntax.css" />
8   </head>
M tmpl/patch.html
+2, -2
 1@@ -1,12 +1,12 @@
 2 {{define "patch"}}
 3 <div>
 4   <h3 class="text-lg m-0 p-0 mb">
 5-    {{if .Review}}<code class="pill-alert">REVIEW</code>{{end}}
 6+    {{if .Review}}<code class="pill-review">REVIEW</code>{{end}}
 7     <a href="#{{.Url}}">{{.Title}}</a>
 8   </h3>
 9 
10   <div class="group-h text-sm">
11-    <code class="pill{{if .Review}}-alert{{end}}">{{.AuthorName}} &lt;{{.AuthorEmail}}&gt;</code>
12+    <code class="pill{{if .Review}}-review{{end}}">{{.AuthorName}} &lt;{{.AuthorEmail}}&gt;</code>
13     <date>{{.FormattedAuthorDate}}</date>
14   </div>
15 </div>
M tmpl/pr-detail.html
+6, -6
 1@@ -23,14 +23,14 @@
 2 
 3     {{range .Logs}}
 4     <div>
 5-      <code class='pill{{if eq .Event "pr_reviewed"}}-alert{{end}}'>{{.UserName}}</code>
 6+      <code class='pill{{if .UserData.IsAdmin}}-admin{{end}}' title="{{.UserData.Pubkey}}">{{.UserData.Name}}</code>
 7       <span class="font-bold">
 8         {{if eq .Event "pr_created"}}
 9           created pr with <code>{{.FormattedPatchsetID}}</code>
10         {{else if eq .Event "pr_patchset_added"}}
11           added <code>{{.FormattedPatchsetID}}</code>
12         {{else if eq .Event "pr_reviewed"}}
13-          reviewed pr with <code class="pill-alert">{{.FormattedPatchsetID}}</code>
14+          reviewed pr with <code class="pill-review">{{.FormattedPatchsetID}}</code>
15         {{else if eq .Event "pr_patchset_replaced"}}
16           replaced <code>{{.FormattedPatchsetID}}</code>
17         {{else if eq .Event "pr_status_changed"}}
18@@ -55,7 +55,7 @@
19         <summary class="text-sm">Diff ↕</summary>
20         <div class="group">
21           {{range .DiffPatches}}
22-            <div class="box-sm{{if .Review}}-alert{{end}} group" id="{{.Url}}">
23+            <div class="box-sm{{if .Review}}-review{{end}} group" id="{{.Url}}">
24               {{template "patch" .}}
25             </div>
26           {{else}}
27@@ -65,9 +65,9 @@
28       </details>
29 
30       <div>
31-        <code class="{{if .Review}}pill-alert{{end}}">{{.FormattedID}}</code>
32+        <code class="{{if .Review}}pill-review{{end}}">{{.FormattedID}}</code>
33         <span> by </span>
34-        <code class="pill{{if .Review}}-alert{{end}}">{{.UserName}}</code>
35+        <code class="pill{{if .UserData.IsAdmin}}-admin{{end}}" title="{{.UserData.Pubkey}}">{{.UserData.Name}}</code>
36         <span>on <date>{{.Date}}</date></span>
37       </div>
38     {{end}}
39@@ -77,7 +77,7 @@
40 
41   <div class="group">
42     {{range $idx, $val := .Patches}}
43-      <div class="box{{if .Review}}-alert{{end}} group" id="{{.Url}}">
44+      <div class="box{{if .Review}}-review{{end}} group" id="{{.Url}}">
45         {{template "patch" .}}
46       </div>
47     {{else}}
M tmpl/pr-header.html
+1, -1
1@@ -8,7 +8,7 @@
2   <div class="text-sm">
3     {{template "pr-status" .Pr.Status}}
4     <span>opened on <date>{{.Pr.Date}}</date> by</span>
5-    <code class="{{if .Pr.IsAdmin}}pill-alert{{end}}" title="{{.Pr.Pubkey}}">{{.Pr.UserName}}</code>
6+    <code class="pill{{if .Pr.UserData.IsAdmin}}-admin{{end}}" title="{{.Pr.UserData.Pubkey}}">{{.Pr.UserData.Name}}</code>
7   </div>
8 
9   <details>
M tmpl/pr-list-item.html
+1, -1
1@@ -7,7 +7,7 @@
2   <div>
3     <code>#{{.ID}}</code>
4     <span>opened on <date>{{.Date}}</date> by </span>
5-    <code class="{{if .IsAdmin}}pill-alert{{end}}" title="{{.Pubkey}}">{{.UserName}}</code>
6+    <code class="{{if .UserData.IsAdmin}}pill-admin{{end}}" title="{{.UserData.Pubkey}}">{{.UserData.Name}}</code>
7   </div>
8 </div>
9 {{end}}
M tmpl/pr-status.html
+1, -1
1@@ -1,6 +1,6 @@
2 {{define "pr-status"}}
3   {{if eq . "reviewed"}}
4-    <code class="pill-alert">{{.}}</code>
5+    <code class="pill-review">{{.}}</code>
6   {{else if eq . "opened"}}
7     <code class="pill-info">{{.}}</code>
8   {{else if eq . "accepted"}}
M web.go
+63, -37
  1@@ -130,10 +130,12 @@ func repoListHandler(w http.ResponseWriter, r *http.Request) {
  2 			}
  3 			isAdmin := web.Backend.IsAdmin(pk)
  4 			ls = &PrListData{
  5-				ID:       curpr.ID,
  6-				IsAdmin:  isAdmin,
  7-				UserName: repo.User.Name,
  8-				Pubkey:   repo.User.Pubkey,
  9+				ID: curpr.ID,
 10+				UserData: UserData{
 11+					Name:    repo.User.Name,
 12+					IsAdmin: isAdmin,
 13+					Pubkey:  repo.User.Pubkey,
 14+				},
 15 				LinkData: LinkData{
 16 					Url:  template.URL(fmt.Sprintf("/prs/%d", curpr.ID)),
 17 					Text: curpr.Name,
 18@@ -167,18 +169,22 @@ func repoListHandler(w http.ResponseWriter, r *http.Request) {
 19 	}
 20 }
 21 
 22+type UserData struct {
 23+	Name    string
 24+	IsAdmin bool
 25+	Pubkey  string
 26+}
 27+
 28 type MetaData struct {
 29 	URL string
 30 }
 31 
 32 type PrListData struct {
 33 	LinkData
 34-	ID       int64
 35-	IsAdmin  bool
 36-	UserName string
 37-	Pubkey   string
 38-	Date     string
 39-	Status   string
 40+	UserData
 41+	ID     int64
 42+	Date   string
 43+	Status string
 44 }
 45 
 46 type RepoDetailData struct {
 47@@ -233,10 +239,12 @@ func repoDetailHandler(w http.ResponseWriter, r *http.Request) {
 48 		}
 49 		isAdmin := web.Backend.IsAdmin(pk)
 50 		ls := PrListData{
 51-			ID:       curpr.ID,
 52-			IsAdmin:  isAdmin,
 53-			UserName: user.Name,
 54-			Pubkey:   user.Pubkey,
 55+			ID: curpr.ID,
 56+			UserData: UserData{
 57+				Name:    user.Name,
 58+				IsAdmin: isAdmin,
 59+				Pubkey:  user.Pubkey,
 60+			},
 61 			LinkData: LinkData{
 62 				Url:  template.URL(fmt.Sprintf("/prs/%d", curpr.ID)),
 63 				Text: curpr.Name,
 64@@ -276,13 +284,11 @@ func repoDetailHandler(w http.ResponseWriter, r *http.Request) {
 65 }
 66 
 67 type PrData struct {
 68-	ID       int64
 69-	IsAdmin  bool
 70-	Title    string
 71-	Date     string
 72-	UserName string
 73-	Pubkey   string
 74-	Status   string
 75+	UserData
 76+	ID     int64
 77+	Title  string
 78+	Date   string
 79+	Status string
 80 }
 81 
 82 type PatchData struct {
 83@@ -295,17 +301,15 @@ type PatchData struct {
 84 
 85 type EventLogData struct {
 86 	*EventLog
 87+	UserData
 88 	FormattedPatchsetID string
 89-	UserName            string
 90-	Pubkey              string
 91 	Date                string
 92 }
 93 
 94 type PatchsetData struct {
 95 	*Patchset
 96+	UserData
 97 	FormattedID string
 98-	UserName    string
 99-	Pubkey      string
100 	Date        string
101 	DiffPatches []PatchData
102 }
103@@ -392,11 +396,21 @@ func prDetailHandler(w http.ResponseWriter, r *http.Request) {
104 			})
105 		}
106 
107+		pk, err := web.Backend.PubkeyToPublicKey(user.Pubkey)
108+		if err != nil {
109+			web.Logger.Error("cannot parse pubkey for pr user", "err", err)
110+			w.WriteHeader(http.StatusUnprocessableEntity)
111+			return
112+		}
113+
114 		patchsetsData = append(patchsetsData, PatchsetData{
115 			Patchset:    patchset,
116 			FormattedID: getFormattedPatchsetID(patchset.ID),
117-			UserName:    user.Name,
118-			Pubkey:      user.Pubkey,
119+			UserData: UserData{
120+				Name:    user.Name,
121+				IsAdmin: web.Backend.IsAdmin(pk),
122+				Pubkey:  user.Pubkey,
123+			},
124 			Date:        patchset.CreatedAt.Format(time.RFC3339),
125 			DiffPatches: patchesData,
126 		})
127@@ -469,12 +483,22 @@ func prDetailHandler(w http.ResponseWriter, r *http.Request) {
128 	logData := []EventLogData{}
129 	for _, eventlog := range logs {
130 		user, _ := web.Pr.GetUserByID(eventlog.UserID)
131+		pk, err := web.Backend.PubkeyToPublicKey(user.Pubkey)
132+		if err != nil {
133+			web.Logger.Error("cannot parse pubkey for pr user", "err", err)
134+			w.WriteHeader(http.StatusUnprocessableEntity)
135+			return
136+		}
137+
138 		logData = append(logData, EventLogData{
139 			EventLog:            eventlog,
140 			FormattedPatchsetID: getFormattedPatchsetID(eventlog.PatchsetID.Int64),
141-			UserName:            user.Name,
142-			Pubkey:              user.Pubkey,
143-			Date:                pr.CreatedAt.Format(web.Backend.Cfg.TimeFormat),
144+			UserData: UserData{
145+				Name:    user.Name,
146+				IsAdmin: web.Backend.IsAdmin(pk),
147+				Pubkey:  user.Pubkey,
148+			},
149+			Date: pr.CreatedAt.Format(web.Backend.Cfg.TimeFormat),
150 		})
151 	}
152 
153@@ -489,13 +513,15 @@ func prDetailHandler(w http.ResponseWriter, r *http.Request) {
154 		Patchsets: patchsetsData,
155 		Logs:      logData,
156 		Pr: PrData{
157-			ID:       pr.ID,
158-			IsAdmin:  isAdmin,
159-			Title:    pr.Name,
160-			UserName: user.Name,
161-			Pubkey:   user.Pubkey,
162-			Date:     pr.CreatedAt.Format(web.Backend.Cfg.TimeFormat),
163-			Status:   pr.Status,
164+			ID: pr.ID,
165+			UserData: UserData{
166+				Name:    user.Name,
167+				IsAdmin: isAdmin,
168+				Pubkey:  user.Pubkey,
169+			},
170+			Title:  pr.Name,
171+			Date:   pr.CreatedAt.Format(web.Backend.Cfg.TimeFormat),
172+			Status: pr.Status,
173 		},
174 		MetaData: MetaData{
175 			URL: web.Backend.Cfg.Url,