Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

render.gno

5.43 Kb · 144 lines
  1package directory
  2
  3import (
  4	"net/url"
  5	"strconv"
  6	"strings"
  7
  8	"gno.land/p/g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm/remixlab/core/v1"
  9	"gno.land/p/g1lnkytfqcjwllws63gvf0mv9yt04aswy4y9amhm/remixlab/render/v1"
 10)
 11
 12// Render serves the native pages: overview, accepted entries, a single
 13// entry, the review queue, members and rules.
 14func Render(path string) string {
 15	if members == nil {
 16		return render.Heading(1, appTitle) + "This app is not initialized.\n"
 17	}
 18	segs, q := render.ParsePath(path)
 19	switch {
 20	case len(segs) == 0:
 21		return renderHome()
 22	case segs[0] == "entries" && len(segs) == 1:
 23		return renderList("Entries", "entries", core.SubmissionAccepted, q)
 24	case segs[0] == "entries" && len(segs) == 2:
 25		id, err := strconv.ParseUint(segs[1], 10, 64)
 26		if err != nil {
 27			return notFound()
 28		}
 29		return renderEntry(id)
 30	case segs[0] == "queue" && len(segs) == 1:
 31		return renderList("Review queue", "queue", core.SubmissionSubmitted, q)
 32	case segs[0] == "members" && len(segs) == 1:
 33		return renderMembers(render.Page(q, render.PageCount(members.Size(), pageSize)))
 34	case segs[0] == "rules" && len(segs) == 1:
 35		return renderRules()
 36	}
 37	return notFound()
 38}
 39
 40func renderHome() string {
 41	accepted := entries.CountByStatus(core.SubmissionAccepted)
 42	waiting := entries.CountByStatus(core.SubmissionSubmitted)
 43	var sb strings.Builder
 44	sb.WriteString(render.Heading(1, appTitle))
 45	sb.WriteString("Entries are submitted for review; accepted entries are listed here. Every submission, including rejected ones, is public chain data.\n\n")
 46	sb.WriteString("- " + render.Link("Entries", render.RealmURL(pkgPath, "entries")) + " (" + strconv.Itoa(accepted) + ")\n")
 47	sb.WriteString("- " + render.Link("Review queue", render.RealmURL(pkgPath, "queue")) + " (" + strconv.Itoa(waiting) + ")\n")
 48	sb.WriteString("- " + render.Link("Members", render.RealmURL(pkgPath, "members")) + " (" + strconv.Itoa(members.Size()) + ")\n")
 49	sb.WriteString("- " + render.Link("Rules", render.RealmURL(pkgPath, "rules")) + "\n\n")
 50	sb.WriteString(render.TxLink("Submit an entry", pkgPath, "Submit") + " · " + render.TxLink("Join (requires an invitation)", pkgPath, "Join") + "\n\n")
 51	sb.WriteString(renderTable(entries.Submissions(int(core.SubmissionAccepted), 0, 5), false))
 52	sb.WriteString("_Recipe " + render.Text(recipeID+"@"+recipeVersion) + ". Membership is address-based; one address is not one person._\n")
 53	return sb.String()
 54}
 55
 56func renderList(heading, route string, status core.SubmissionStatus, q url.Values) string {
 57	pages := render.PageCount(entries.CountByStatus(status), pageSize)
 58	page := render.Page(q, pages)
 59	list := entries.Submissions(int(status), (page-1)*pageSize, pageSize)
 60	return render.Heading(1, heading) +
 61		renderTable(list, status == core.SubmissionSubmitted) +
 62		render.Pager(pkgPath, route, page, pages)
 63}
 64
 65func renderTable(list []core.SubmissionView, reviewActions bool) string {
 66	if len(list) == 0 {
 67		return "Nothing here yet.\n\n"
 68	}
 69	var rows [][]string
 70	for _, v := range list {
 71		idStr := strconv.FormatUint(v.ID, 10)
 72		row := []string{
 73			render.Link("#"+idStr, render.RealmURL(pkgPath, "entries/"+idStr)),
 74			render.Text(v.Answers[titleIndex]),
 75		}
 76		if reviewActions {
 77			row = append(row, reviewLinks(idStr))
 78		}
 79		rows = append(rows, render.TrustedRow(row...))
 80	}
 81	headers := []string{"Entry", "Title"}
 82	if reviewActions {
 83		headers = append(headers, "Review")
 84	}
 85	return render.Table(headers, rows)
 86}
 87
 88func renderEntry(id uint64) string {
 89	v, ok := entries.Submission(id)
 90	if !ok {
 91		return notFound()
 92	}
 93	idStr := strconv.FormatUint(id, 10)
 94	if v.Status == core.SubmissionRejected {
 95		return render.Heading(1, "Entry #"+idStr) + "This entry was rejected.\n\n" +
 96			render.Link("All entries", render.RealmURL(pkgPath, "entries")) + "\n"
 97	}
 98	var sb strings.Builder
 99	sb.WriteString(render.Heading(1, v.Answers[titleIndex]))
100	sb.WriteString("Status: **" + v.Status.String() + "** · submitted by " + render.Code(v.Submitter.String()) + "\n\n")
101	var rows [][]string
102	for i, f := range entries.Fields() {
103		if i != titleIndex && v.Answers[i] != "" {
104			rows = append(rows, render.Row(f.Label, v.Answers[i]))
105		}
106	}
107	if len(rows) > 0 {
108		sb.WriteString(render.Table([]string{"Field", "Answer"}, rows))
109	}
110	if v.Status == core.SubmissionSubmitted {
111		sb.WriteString("Awaiting review: " + reviewLinks(idStr) + "\n\n")
112	}
113	sb.WriteString(render.Link("All entries", render.RealmURL(pkgPath, "entries")) + "\n")
114	return sb.String()
115}
116
117func reviewLinks(idStr string) string {
118	return render.TxLink("accept", pkgPath, "Accept", "id", idStr) + " · " +
119		render.TxLink("reject", pkgPath, "Reject", "id", idStr)
120}
121
122func renderMembers(page int) string {
123	var rows [][]string
124	for _, m := range members.List((page-1)*pageSize, pageSize) {
125		rows = append(rows, render.Row(m.Address.String(), m.Role.String()))
126	}
127	return render.Heading(1, "Members") +
128		render.Table([]string{"Address", "Role"}, rows) +
129		render.Pager(pkgPath, "members", page, render.PageCount(members.Size(), pageSize))
130}
131
132func renderRules() string {
133	var rows [][]string
134	for _, r := range policy.List() {
135		rows = append(rows, render.Row(r.Op, r.Rule.String(), r.Floor.String()))
136	}
137	return render.Heading(1, "Rules") +
138		render.Table([]string{"Operation", "Who may", "Most permissive allowed"}, rows) +
139		"Up to 100 pending or accepted submissions, at most 3 per address. Review decisions are final; rejecting an entry frees its slot." + "\n"
140}
141
142func notFound() string {
143	return render.Heading(1, "Not found") + render.Link("Back to the app", render.RealmURL(pkgPath, "")) + "\n"
144}