git ssb

0+

ev / microbay



forked from Dominic / patchbay

Commit b0f09a2c61341125b8d3bbbaac3e7db729e6db79

Add git issue and pull request creation UI

Charles Lehner committed on 8/28/2016, 4:55:43 AM
Parent: d4a98043304f590b79f4dbe3398066294b7dba14

Files changed

modules/git.jschanged
package.jsonchanged
modules/git.jsView
@@ -1,12 +1,15 @@
11 var h = require('hyperscript')
22 var pull = require('pull-stream')
33 var paramap = require('pull-paramap')
4+var cat = require('pull-cat')
45 var human = require('human-time')
6+var combobox = require('hypercombo')
57
68 var plugs = require('../plugs')
79 var message_link = plugs.first(exports.message_link = [])
810 var message_confirm = plugs.first(exports.message_confirm = [])
11+var message_compose = plugs.first(exports.message_compose = [])
912 var sbot_links = plugs.first(exports.sbot_links = [])
1013 var sbot_links2 = plugs.first(exports.sbot_links2 = [])
1114 var sbot_get = plugs.first(exports.sbot_get = [])
1215 var getAvatar = require('ssb-avatar')
@@ -18,8 +21,63 @@
1821 function shortRefName(ref) {
1922 return ref.replace(/^refs\/(heads|tags)\//, '')
2023 }
2124
25+function getRefs(msg) {
26+ var refs = {}
27+ var commitTitles = {}
28+ return pull(
29+ sbot_links({
30+ reverse: true,
31+ source: msg.value.author,
32+ dest: msg.key,
33+ rel: 'repo',
34+ values: true
35+ }),
36+ pull.map(function (link) {
37+ var refUpdates = link.value.content.refs || {}
38+ var commits = link.value.content.commits
39+ if(commits) {
40+ for(var i = 0; i < commits.length; i++) {
41+ var commit = commits[i]
42+ if(commit && commit.sha1 && commit.title) {
43+ commitTitles[commit.sha1] = commit.title
44+ }
45+ }
46+ }
47+ return Object.keys(refUpdates).reverse().map(function (ref) {
48+ if(refs[ref]) return
49+ refs[ref] = true
50+ var rev = refUpdates[ref]
51+ if(!rev) return
52+ return {
53+ name: ref,
54+ rev: rev,
55+ link: link,
56+ title: commitTitles[rev],
57+ }
58+ }).filter(Boolean)
59+ }),
60+ pull.flatten()
61+ )
62+}
63+
64+function getForks(id) {
65+ return pull(
66+ sbot_links({
67+ reverse: true,
68+ dest: id,
69+ rel: 'upstream'
70+ }),
71+ pull.map(function (link) {
72+ return {
73+ id: link.key,
74+ author: link.source
75+ }
76+ })
77+ )
78+}
79+
2280 function repoLink(id) {
2381 var el = h('a', {href: '#'+id}, id.substr(0, 10) + '…')
2482 getAvatar({links: sbot_links}, self_id, id, function (err, avatar) {
2583 if(err) return console.error(err)
@@ -127,40 +185,28 @@
127185 h('th', 'closed pull requests'))))),
128186 h('div.git-table-wrapper',
129187 h('table',
130188 forksT = tableRows(h('tr',
131- h('th', 'forks'))))))
189+ h('th', 'forks'))))),
190+ h('div', h('a', {href: '#', onclick: function () {
191+ this.parentNode.replaceChild(issueForm(msg), this)
192+ }}, 'New Issue…')),
193+ h('div', h('a', {href: '#', onclick: function () {
194+ this.parentNode.replaceChild(pullRequestForm(msg), this)
195+ }}, 'New Pull Request…')))
132196
133- // compute refs
134- var refs = {}
135- pull(
136- sbot_links({
137- reverse: true,
138- source: msg.value.author,
139- dest: msg.key,
140- rel: 'repo',
141- values: true
142- }),
143- pull.drain(function (link) {
144- var refUpdates = link.value.content.refs || {}
145- Object.keys(refUpdates).reverse().filter(function (ref) {
146- if (refs[ref]) return
147- refs[ref] = true
148- var rev = refUpdates[ref]
149- if (!rev) return
150- var parts = /^refs\/(heads|tags)\/(.*)$/.exec(ref) || []
151- var t
152- if (parts[1] === 'heads') t = branchesT
153- else if (parts[1] === 'tags') t = tagsT
154- if (t) t.append(h('tr',
155- h('td', parts[2]),
156- h('td', h('code', rev)),
157- h('td', messageTimestampLink(link))))
158- })
159- }, function (err) {
160- if (err) console.error(err)
161- })
162- )
197+ pull(getRefs(msg), pull.drain(function (ref) {
198+ var parts = /^refs\/(heads|tags)\/(.*)$/.exec(ref.name) || []
199+ var t
200+ if(parts[1] === 'heads') t = branchesT
201+ else if(parts[1] === 'tags') t = tagsT
202+ if(t) t.append(h('tr',
203+ h('td', parts[2]),
204+ h('td', h('code', ref.rev)),
205+ h('td', messageTimestampLink(ref.link))))
206+ }, function (err) {
207+ if(err) console.error(err)
208+ }))
163209
164210 // list issues and pull requests
165211 pull(
166212 sbot_links({
@@ -197,17 +243,13 @@
197243 )
198244
199245 // list forks
200246 pull(
201- sbot_links({
202- reverse: true,
203- dest: msg.key,
204- rel: 'upstream'
205- }),
206- pull.drain(function (link) {
247+ getForks(msg.key),
248+ pull.drain(function (fork) {
207249 forksT.append(h('tr', h('td',
208- repoName(link.key, true),
209- ' by ', h('a', {href: '#'+link.source}, avatar_name(link.source)))))
250+ repoName(fork.id, true),
251+ ' by ', h('a', {href: '#'+fork.author}, avatar_name(fork.author)))))
210252 }, function (err) {
211253 if (err) console.error(err)
212254 })
213255 )
@@ -285,8 +327,117 @@
285327 return el
286328 }
287329 }
288330
331+function findMessageContent(el) {
332+ for(; el; el = el.parentNode) {
333+ if(el.classList.contains('message')) {
334+ return el.querySelector('.message_content')
335+ }
336+ }
337+}
338+
339+function issueForm(msg, contentEl) {
340+ return h('form',
341+ h('strong', 'New Issue:'),
342+ message_compose(
343+ {type: 'issue', project: msg.key},
344+ function (value) { return value },
345+ function (err, issue) {
346+ if(err) return alert(err)
347+ if(!issue) return
348+ var title = issue.value.content.text
349+ if(title.length > 70) title = title.substr(0, 70) + '…'
350+ form.appendChild(h('div',
351+ h('a', {href: '#'+issue.key}, title)
352+ ))
353+ }
354+ )
355+ )
356+}
357+
358+function branchMenu(msg, full) {
359+ return combobox({
360+ style: {'max-width': '14ex'},
361+ placeholder: 'branch…',
362+ default: 'master',
363+ read: msg && pull(getRefs(msg), pull.map(function (ref) {
364+ var m = /^refs\/heads\/(.*)$/.exec(ref.name)
365+ if(!m) return
366+ var branch = m[1]
367+ var label = branch
368+ if(full) {
369+ var updated = new Date(ref.link.value.timestamp)
370+ label = branch +
371+ ' · ' + human(updated) +
372+ ' · ' + ref.rev.substr(1, 8) +
373+ (ref.title ? ' · "' + ref.title + '"' : '')
374+ }
375+ return h('option', {value: branch}, label)
376+ }))
377+ })
378+}
379+
380+function pullRequestForm(msg) {
381+ var headRepoInput
382+ var headBranchInput = branchMenu()
383+ var branchInput = branchMenu(msg)
384+ var form = h('form',
385+ h('strong', 'New Pull Request:'),
386+ h('div',
387+ 'from ',
388+ headRepoInput = combobox({
389+ style: {'max-width': '26ex'},
390+ onchange: function () {
391+ // list branches for selected repo
392+ var repoId = this.value
393+ if(repoId) sbot_get(repoId, function (err, value) {
394+ if(err) console.error(err)
395+ var msg = value && {key: repoId, value: value}
396+ headBranchInput = headBranchInput.swap(branchMenu(msg, true))
397+ })
398+ else headBranchInput = headBranchInput.swap(branchMenu())
399+ },
400+ read: pull(cat([
401+ pull.once({id: msg.key, author: msg.value.author}),
402+ getForks(msg.key)
403+ ]), pull.map(function (fork) {
404+ return h('option', {value: fork.id},
405+ repoName(fork.id), ' by ', avatar_name(fork.author))
406+ }))
407+ }),
408+ ':',
409+ headBranchInput,
410+ ' to ',
411+ repoName(msg.key),
412+ ':',
413+ branchInput),
414+ message_compose(
415+ {
416+ type: 'pull-request',
417+ project: msg.key,
418+ repo: msg.key,
419+ },
420+ function (value) {
421+ value.branch = branchInput.value
422+ value.head_repo = headRepoInput.value
423+ value.head_branch = headBranchInput.value
424+ return value
425+ },
426+ function (err, issue) {
427+ if(err) return alert(err)
428+ if(!issue) return
429+ var title = issue.value.content.text
430+ if(title.length > 70) title = title.substr(0, 70) + '…'
431+ form.appendChild(h('div',
432+ h('a', {href: '#'+issue.key}, title)
433+ ))
434+ }
435+ )
436+ )
437+ return form
438+}
439+
289440 exports.message_action = function (msg, sbot) {
290441 var c = msg.value.content
291442 if(c.type === 'issue' || c.type === 'pull-request') {
292443 var isOpen
package.jsonView
@@ -12,8 +12,9 @@
1212 "dataurl-": "^0.1.0",
1313 "depject": "^1.0.1",
1414 "hjson": "^2.0.3",
1515 "human-time": "0.0.1",
16+ "hypercombo": "0.1.0",
1617 "hypercrop": "^1.0.1",
1718 "hyperfile": "^1.1.0",
1819 "hyperlightbox": "^0.1.3",
1920 "hyperprogress": "0.1.0",

Built with git-ssb-web