git ssb

16+

Dominic / patchbay



Commit 52daeae1fcff1fca37ecf65e1ff73d7a80bea2cf

merge git

Dominic Tarr committed on 7/25/2016, 5:07:09 AM
Parent: 7cd71189c60f0dfdcbeda721fa54776e85d69a0e
Parent: 6bd94bf8ab683004a0730dbb0b860ef5e8cd28a1

Files changed

modules/index.jschanged
modules/git.jsadded
style.csschanged
modules/index.jsView
@@ -12,8 +12,9 @@
1212 "feed.js": require('./feed.js'),
1313 "file-input.js": require('./file-input.js'),
1414 "follow.js": require('./follow.js'),
1515 "relationships.js": require('./relationships.js'),
16+ "git.js": require('./git.js'),
1617 "invite.js": require('./invite.js'),
1718 "like.js": require('./like.js'),
1819 "markdown.js": require('./markdown.js'),
1920 "message-confirm.js": require('./message-confirm.js'),
@@ -33,4 +34,7 @@
3334 "tabs.js": require('./tabs.js'),
3435 "thread.js": require('./thread.js'),
3536 "timestamp.js": require('./timestamp.js')
3637 }
38+
39+
40+
modules/git.jsView
@@ -1,0 +1,250 @@
1+var h = require('hyperscript')
2+var pull = require('pull-stream')
3+var paramap = require('pull-paramap')
4+var moment = require('moment')
5+
6+var plugs = require('../plugs')
7+var message_link = plugs.first(exports.message_link = [])
8+var sbot_links = plugs.first(exports.sbot_links = [])
9+var sbot_links2 = plugs.first(exports.sbot_links2 = [])
10+var sbot_get = plugs.first(exports.sbot_get = [])
11+var getAvatar = require('ssb-avatar')
12+var avatar_name = plugs.first(exports.avatar_name = [])
13+var markdown = plugs.first(exports.markdown = [])
14+
15+var self_id = require('../keys').id
16+
17+function shortRefName(ref) {
18+ return ref.replace(/^refs\/(heads|tags)\//, '')
19+}
20+
21+function repoLink(id) {
22+ var el = h('a', {href: '#'+id}, id.substr(0, 10) + '…')
23+ getAvatar({links: sbot_links}, self_id, id, function (err, avatar) {
24+ if(err) return console.error(err)
25+ el.textContent = avatar.name
26+ })
27+ return el
28+}
29+
30+function getIssueState(id, cb) {
31+ pull(
32+ sbot_links({dest: id, rel: 'issues', values: true}),
33+ pull.map(function (msg) {
34+ var issues = msg.value.content.issues
35+ if (!Array.isArray(issues)) return
36+ return issues.filter(function (issue) {
37+ return issue.link === id
38+ }).map(function (issue) {
39+ return {
40+ ts: msg.value.timestamp,
41+ open: issue.open,
42+ merged: issue.merged,
43+ }
44+ })
45+ }),
46+ pull.flatten(),
47+ pull.collect(function (err, updates) {
48+ if (err) return cb(err)
49+ var open = true, merged = false
50+ updates.sort(function (a, b) {
51+ return b.ts - a.ts
52+ }).forEach(function (update) {
53+ if (update.open != null)
54+ open = update.open
55+ if (update.merged != null)
56+ merged = update.merged
57+ })
58+ cb(null, open ? 'open' : merged ? 'merged' : 'closed')
59+ })
60+ )
61+}
62+
63+function messageTimestampLink(msg) {
64+ var m = moment(msg.value.timestamp)
65+ return h('a.timestamp', {
66+ timestamp: m,
67+ title: m.format('LLLL'),
68+ href: '#'+msg.key
69+ }, m.fromNow())
70+}
71+
72+function tableRows(headerRow) {
73+ var thead = h('thead'), tbody = h('tbody')
74+ var first = true
75+ var t = [thead, tbody]
76+ t.append = function (row) {
77+ if (first) {
78+ first = false
79+ thead.appendChild(headerRow)
80+ }
81+ tbody.appendChild(row)
82+ }
83+ return t
84+}
85+
86+function repoName(id, link) {
87+ var el = link
88+ ? h('a', {href: '#'+id}, id.substr(0, 8) + '…')
89+ : h('ins', id.substr(0, 8) + '…')
90+ getAvatar({links: sbot_links}, self_id, id, function (err, avatar) {
91+ if(err) return console.error(err)
92+ el.textContent = avatar.name
93+ })
94+ return el
95+}
96+
97+exports.message_content = function (msg, sbot) {
98+ var c = msg.value.content
99+
100+ if(c.type === 'git-repo') {
101+ var nameEl
102+ var branchesT, tagsT, openIssuesT, closedIssuesT, openPRsT, closedPRsT
103+ var div = h('div',
104+ h('p', 'git repo ', repoName(msg.key)),
105+ c.upstream ? h('p', 'fork of ', repoName(c.upstream, true)) : '',
106+ h('p', h('code', 'ssb://' + msg.key)),
107+ h('div.git-table-wrapper', {style: {'max-height': '12em'}},
108+ h('table',
109+ branchesT = tableRows(h('tr',
110+ h('th', 'branch'),
111+ h('th', 'commit'),
112+ h('th', 'last update'))),
113+ tagsT = tableRows(h('tr',
114+ h('th', 'tag'),
115+ h('th', 'commit'),
116+ h('th', 'last update'))))),
117+ h('div.git-table-wrapper', {style: {'max-height': '16em'}},
118+ h('table',
119+ openIssuesT = tableRows(h('tr',
120+ h('th', 'open issues'))),
121+ closedIssuesT = tableRows(h('tr',
122+ h('th', 'closed issues'))))),
123+ h('div.git-table-wrapper', {style: {'max-height': '16em'}},
124+ h('table',
125+ openPRsT = tableRows(h('tr',
126+ h('th', 'open pull requests'))),
127+ closedPRsT = tableRows(h('tr',
128+ h('th', 'closed pull requests'))))))
129+
130+ // compute refs
131+ var refs = {}
132+ pull(
133+ sbot_links({
134+ reverse: true,
135+ source: msg.value.author,
136+ dest: msg.key,
137+ rel: 'repo',
138+ values: true
139+ }),
140+ pull.drain(function (link) {
141+ var refUpdates = link.value.content.refs
142+ for (var ref in refUpdates) {
143+ if (refs[ref]) continue
144+ refs[ref] = true
145+ var rev = refUpdates[ref]
146+ if (!rev) continue
147+ var parts = /^refs\/(heads|tags)\/(.*)$/.exec(ref) || []
148+ var t
149+ if (parts[1] === 'heads') t = branchesT
150+ else if (parts[1] === 'tags') t = tagsT
151+ if (t) t.append(h('tr',
152+ h('td', parts[2]),
153+ h('td', h('code', rev)),
154+ h('td', messageTimestampLink(link))))
155+ }
156+ }, function (err) {
157+ if (err) console.error(err)
158+ })
159+ )
160+
161+ // list issues and pull requests
162+ pull(
163+ sbot_links({
164+ reverse: true,
165+ dest: msg.key,
166+ rel: 'project',
167+ values: true
168+ }),
169+ paramap(function (link, cb) {
170+ getIssueState(link.key, function (err, state) {
171+ if(err) return cb(err)
172+ link.state = state
173+ cb(null, link)
174+ })
175+ }),
176+ pull.drain(function (link) {
177+ var c = link.value.content
178+ // TODO: support renamed issues
179+ var title = c.title || (c.text ? c.text.length > 30
180+ ? c.text.substr(0, 30) + '…'
181+ : c.text : link.key)
182+ var author = link.value.author
183+ var t = c.type === 'pull-request'
184+ ? link.state === 'open' ? openPRsT : closedPRsT
185+ : link.state === 'open' ? openIssuesT : closedIssuesT
186+ t.append(h('tr',
187+ h('td',
188+ h('a', {href: '#'+link.key}, title), h('br'),
189+ h('small',
190+ 'opened ', messageTimestampLink(link),
191+ ' by ', h('a', {href: '#'+author}, avatar_name(author))))))
192+ }, function (err) {
193+ if (err) console.error(err)
194+ })
195+ )
196+
197+ return div
198+ }
199+
200+ if(c.type === 'git-update') {
201+ return h('p',
202+ 'pushed to ',
203+ repoLink(c.repo),
204+ c.refs ? h('ul', Object.keys(c.refs).map(function (ref) {
205+ var rev = c.refs[ref]
206+ return h('li',
207+ shortRefName(ref) + ': ',
208+ rev ? h('code', rev) : h('em', 'deleted'))
209+ })) : null,
210+ Array.isArray(c.issues) ? c.issues.map(function (issue) {
211+ if (issue.merged === true)
212+ return ['Merged ', message_link(issue.link), ' in ',
213+ h('code', issue.object), ' ', h('q', issue.label)]
214+ if (issue.open === false)
215+ return ['Closed ', message_link(issue.link), ' in ',
216+ h('code', issue.object), ' ', h('q', issue.label)]
217+ }) : null
218+ )
219+ }
220+
221+ if (c.type === 'issue') {
222+ return h('div',
223+ h('p', 'opened issue on ', repoLink(c.project)),
224+ c.title ? h('h4', c.title) : '',
225+ markdown(c)
226+ )
227+ }
228+
229+ if (c.type === 'pull-request') {
230+ return h('div',
231+ h('p', 'opened pull-request ',
232+ 'to ', repoLink(c.repo), ':', c.branch, ' ',
233+ 'from ', repoLink(c.head_repo), ':', c.head_branch),
234+ c.title ? h('h4', c.title) : '',
235+ markdown(c)
236+ )
237+ }
238+}
239+
240+exports.message_meta = function (msg, sbot) {
241+ var type = msg.value.content.type
242+ if (type == 'issue' || type == 'pull-request') {
243+ var el = h('em', '...')
244+ getIssueState(msg.key, function (err, state) {
245+ if (err) return console.error(err)
246+ el.textContent = state
247+ })
248+ return el
249+ }
250+}
style.cssView
@@ -288,4 +288,16 @@
288288 border: 1px solid #ccc;
289289 }
290290
291291
292+.git-table-wrapper {
293+ max-height: 12em;
294+ overflow: auto;
295+ word-break: break-all;
296+ margin: 1em 0;
297+}
298+
299+.git-table-wrapper table {
300+ width: 100%;
301+}
302+
303+

Built with git-ssb-web