git ssb

30+

cel / git-ssb-web



Tree: fbf36ab9f3e81a1c5b6e0b4c6eed51005e6e07ab

Files: fbf36ab9f3e81a1c5b6e0b4c6eed51005e6e07ab / lib / repos / issues.js

8583 bytesRaw
1var pull = require('pull-stream')
2var cat = require('pull-cat')
3var u = require('../util')
4var markdown = require('../markdown')
5var forms = require('../forms')
6
7module.exports = function (repoRoutes, web) {
8 return new RepoIssueRoutes(repoRoutes, web)
9}
10
11function RepoIssueRoutes(repoRoutes, web) {
12 this.repo = repoRoutes
13 this.web = web
14}
15
16var I = RepoIssueRoutes.prototype
17
18function getMention(msg, id) {
19 if (msg.key == id) return msg
20 var mentions = msg.value.content.mentions
21 if (mentions) for (var i = 0; i < mentions.length; i++) {
22 var mention = mentions[i]
23 if (mention.link == id)
24 return mention
25 }
26 return null
27}
28
29/* Issues */
30
31I.serveRepoIssues = function (req, repo, isPRs) {
32 var self = this
33 var count = 0
34 var state = req._u.query.state || 'open'
35 var newPath = isPRs ? [repo.id, 'compare'] : [repo.id, 'issues', 'new']
36 var title = req._t('Issues') + ' · %{author}/%{repo}'
37 var page = isPRs ? 'pulls' : 'issues'
38 return self.repo.renderRepoPage(req, repo, page, null, title, cat([
39 pull.once(
40 (self.web.isPublic ? '' :
41 '<form class="right-bar" method="get"' +
42 ' action="' + u.encodeLink(newPath) + '">' +
43 '<button class="btn">&plus; ' +
44 req._t(isPRs ? 'pullRequest.New' : 'issue.New') +
45 '</button>' +
46 '</form>') +
47 '<h3>' + req._t(isPRs ? 'PullRequests' : 'Issues') + '</h3>' +
48 u.nav([
49 ['?', req._t('issues.Open'), 'open'],
50 ['?state=closed', req._t('issues.Closed'), 'closed'],
51 ['?state=all', req._t('issues.All'), 'all']
52 ], state)),
53 pull(
54 (isPRs ? self.web.pullReqs : self.web.issues).list({
55 repo: repo.id,
56 project: repo.id,
57 reverse: true,
58 open: {open: true, closed: false}[state]
59 }),
60 pull.map(function (issue) {
61 count++
62 var state = (issue.open ? 'open' : 'closed')
63 var stateStr = req._t(issue.open ?
64 'issue.state.Open' : 'issue.state.Closed')
65 return '<section class="collapse">' +
66 '<i class="issue-state issue-state-' + state + '"' +
67 ' title="' + stateStr + '">◼</i> ' +
68 '<a href="' + u.encodeLink(issue.id) + '">' +
69 u.escape(issue.title) +
70 '<span class="right-bar">' +
71 new Date(issue.created_at).toLocaleString(req._locale) +
72 '</span>' +
73 '</a>' +
74 '</section>'
75 })
76 ),
77 u.readOnce(function (cb) {
78 cb(null, count > 0 ? '' :
79 '<p>' + req._t(isPRs ? 'NoPullRequests' : 'NoIssues') + '</p>')
80 })
81 ]))
82}
83
84/* New Issue */
85
86I.serveRepoNewIssue = function (req, repo, issueId, path) {
87 var title = req._t('issue.New') + ' · %{author}/%{repo}'
88 return this.repo.renderRepoPage(req, repo, 'issues', null, title, pull.once(
89 '<h3>' + req._t('issue.New') + '</h3>' +
90 '<section><form action="" method="post">' +
91 '<input type="hidden" name="action" value="new-issue">' +
92 '<p><input class="wide-input" name="title" placeholder="' +
93 req._t('issue.Title') + '" size="77" /></p>' +
94 forms.post(req, repo, req._t('Description'), 8) +
95 '<button type="submit" class="btn">' + req._t('Create') + '</button>' +
96 '</form></section>'))
97}
98
99/* Issue */
100
101I.serveRepoIssue = function (req, repo, issue, path, postId) {
102 var self = this
103 var isAuthor = (self.web.myId == issue.author)
104 || (self.web.myId == repo.feed)
105 var newestMsg = {key: issue.id, value: {timestamp: issue.created_at}}
106 var title = u.escape(issue.title) + ' · %{author}/%{repo}'
107 return self.repo.renderRepoPage(req, repo, 'issues', null, title, cat([
108 pull.once(
109 forms.name(req, !self.web.isPublic, issue.id, issue.title,
110 'issue-title', null, req._t('issue.Rename'),
111 '<h3>' + u.link([issue.id], issue.title) + '</h3>') +
112 '<code>' + issue.id + '</code>' +
113 '<section class="collapse">' +
114 (issue.open
115 ? '<strong class="issue-status open">' +
116 req._t('issue.state.Open') + '</strong>'
117 : '<strong class="issue-status closed">' +
118 req._t('issue.state.Closed') + '</strong>')),
119 u.readOnce(function (cb) {
120 self.web.about.getName(issue.author, function (err, authorName) {
121 if (err) return cb(err)
122 var authorLink = u.link([issue.author], authorName)
123 cb(null, req._t('issue.Opened',
124 {name: authorLink, datetime: u.timestamp(issue.created_at, req)}))
125 })
126 }),
127 pull.once('<hr/>' + markdown(issue.text, repo) + '</section>'),
128 // render posts and edits
129 pull(
130 self.web.ssb.links({
131 dest: issue.id,
132 values: true
133 }),
134 pull.unique('key'),
135 self.web.addAuthorName(),
136 u.sortMsgs(),
137 pull.through(function (msg) {
138 // the newest message in the issue thread
139 // becomes the branch of the new post
140 if (msg.value
141 && msg.value.timestamp > newestMsg.value.timestamp
142 && msg.value.content.root == issue.id)
143 newestMsg = msg
144 }),
145 pull.map(self.renderIssueActivityMsg.bind(self, req, repo, issue,
146 req._t('issue.'), postId))
147 ),
148 self.web.isPublic ? pull.empty() : u.readOnce(function (cb) {
149 cb(null, forms.issueComment(req, issue, repo,
150 newestMsg.key, isAuthor, req._t('issue.')))
151 })
152 ]))
153}
154
155I.renderIssueActivityMsg = function (req, repo, issue, type, postId, msg) {
156 var authorLink = u.link([msg.value.author], msg.authorName)
157 var msgHref = u.encodeLink(msg.key) + '#' + encodeURIComponent(msg.key)
158 var msgTimeLink = '<a href="' + msgHref + '"' +
159 ' name="' + u.escape(msg.key) + '">' +
160 new Date(msg.value.timestamp).toLocaleString(req._locale) + '</a>'
161 var c = msg.value.content
162 switch (c.type) {
163 case 'vote':
164 return ''
165 case 'post':
166 if (c.root == issue.id) {
167 var changed = this.web.issues.isStatusChanged(msg, issue)
168 return '<section class="collapse">' +
169 (msg.key == postId ? '<div class="highlight">' : '') +
170 '<tt class="right-bar item-id">' + msg.key + '</tt> ' +
171 (changed == null ? authorLink : req._t(
172 changed ? 'issue.Reopened' : 'issue.Closed',
173 {name: authorLink, type: type})) +
174 ' &middot; ' + msgTimeLink +
175 (msg.key == postId ? '</div>' : '') +
176 markdown(c.text, repo) +
177 '</section>'
178 } else {
179 var text = c.text || (c.type + ' ' + msg.key)
180 return '<section class="collapse mention-preview">' +
181 req._t('issue.MentionedIn', {
182 name: authorLink,
183 type: type,
184 post: '<a href="/' + msg.key + '#' + msg.key + '">' +
185 String(text).substr(0, 140) + '</a>'
186 }) + '</section>'
187 }
188 case 'issue':
189 case 'pull-request':
190 return '<section class="collapse mention-preview">' +
191 req._t('issue.MentionedIn', {
192 name: authorLink,
193 type: type,
194 post: u.link([msg.key], String(c.title || msg.key).substr(0, 140))
195 }) + '</section>'
196 case 'issue-edit':
197 return '<section class="collapse">' +
198 (msg.key == postId ? '<div class="highlight">' : '') +
199 (c.title == null ? '' : req._t('issue.Renamed', {
200 author: authorLink,
201 type: type,
202 name: '<q>' + u.escape(c.title) + '</q>'
203 })) + ' &middot; ' + msgTimeLink +
204 (msg.key == postId ? '</div>' : '') +
205 '</section>'
206 case 'git-update':
207 var mention = this.web.issues.getMention(msg, issue)
208 if (mention) {
209 var commitLink = u.link([repo.id, 'commit', mention.object],
210 mention.label || mention.object)
211 return '<section class="collapse">' +
212 req._t(mention.open ? 'issue.Reopened' : 'issue.Closed', {
213 name: authorLink,
214 type: type
215 }) + ' &middot; ' + msgTimeLink + '<br/>' +
216 commitLink +
217 '</section>'
218 } else if ((mention = getMention(msg, issue.id))) {
219 var commitLink = u.link(mention.object ?
220 [repo.id, 'commit', mention.object] : [msg.key],
221 mention.label || mention.object || msg.key)
222 return '<section class="collapse">' +
223 req._t('issue.Mentioned', {
224 name: authorLink,
225 type: type
226 }) + ' &middot; ' + msgTimeLink + '<br/>' +
227 commitLink +
228 '</section>'
229 } else {
230 // fallthrough
231 }
232
233 default:
234 return '<section class="collapse">' +
235 authorLink +
236 ' &middot; ' + msgTimeLink +
237 u.json(c) +
238 '</section>'
239 }
240}
241

Built with git-ssb-web