Commit c057842053e5b621b8944a045b087dd563abe19e
Implement inline comment replies; render inline comment threads
cel committed on 11/23/2017, 11:00:55 PMParent: 63bcff079120449a73ea2cceec00484d3378041c
Files changed
index.js | changed |
lib/forms.js | changed |
lib/repos/index.js | changed |
lib/repos/pulls.js | changed |
locale/en.json | changed |
locale/eo.json | changed |
schemas.md | changed |
static/styles.css | changed |
index.js | |||
---|---|---|---|
@@ -334,8 +334,11 @@ | |||
334 | 334 … | new ParamError('missing repo id'), 400)) | |
335 | 335 … | if (!data.commitId) | |
336 | 336 … | return cb(null, self.serveError(req, | |
337 | 337 … | new ParamError('missing commit id'), 400)) | |
338 … | + if (!data.updateId) | ||
339 … | + return cb(null, self.serveError(req, | ||
340 … | + new ParamError('missing update id'), 400)) | ||
338 | 341 … | if (!data.filePath) | |
339 | 342 … | return cb(null, self.serveError(req, | |
340 | 343 … | new ParamError('missing file path'), 400)) | |
341 | 344 … | if (!data.line) | |
@@ -344,29 +347,51 @@ | |||
344 | 347 … | var lineNumber = Number(data.line) | |
345 | 348 … | if (isNaN(lineNumber)) | |
346 | 349 … | return cb(null, self.serveError(req, | |
347 | 350 … | new ParamError('bad line number'), 400)) | |
348 | - var repoBranches = data.repoBranch | ||
349 | - ? data.repoBranch.split(',') : '' | ||
350 | 351 … | var msg = { | |
351 | 352 … | type: 'line-comment', | |
352 | 353 … | text: data.text, | |
353 | 354 … | repo: data.repo, | |
354 | - repoBranch: repoBranches, | ||
355 … | + updateId: data.updateId, | ||
355 | 356 … | commitId: data.commitId, | |
356 | 357 … | filePath: data.filePath, | |
357 | 358 … | line: lineNumber, | |
358 | 359 … | } | |
359 | 360 … | msg.issue = data.issue | |
360 | 361 … | var mentions = Mentions(data.text) | |
361 | 362 … | if (mentions.length) | |
362 | 363 … | msg.mentions = mentions | |
363 | - return cb(null, self.serveBuffer(200, JSON.stringify(msg, 0, 2))) | ||
364 | 364 … | return self.ssb.publish(msg, function (err) { | |
365 | 365 … | if (err) return cb(null, self.serveError(req, err)) | |
366 | 366 … | cb(null, self.serveRedirect(req, req.url)) | |
367 | 367 … | }) | |
368 | 368 … | ||
369 … | + case 'line-comment-reply': | ||
370 … | + if (!data.root) | ||
371 … | + return cb(null, self.serveError(req, | ||
372 … | + new ParamError('missing thread root'), 400)) | ||
373 … | + if (!data.branch) | ||
374 … | + return cb(null, self.serveError(req, | ||
375 … | + new ParamError('missing thread branch'), 400)) | ||
376 … | + if (!data.text) | ||
377 … | + return cb(null, self.serveError(req, | ||
378 … | + new ParamError('missing post text'), 400)) | ||
379 … | + var msg = { | ||
380 … | + type: 'post', | ||
381 … | + root: data.root, | ||
382 … | + branch: data.branch, | ||
383 … | + text: data.text, | ||
384 … | + } | ||
385 … | + var mentions = Mentions(data.text) | ||
386 … | + if (mentions.length) | ||
387 … | + msg.mentions = mentions | ||
388 … | + return self.ssb.publish(msg, function (err) { | ||
389 … | + if (err) return cb(null, self.serveError(req, err)) | ||
390 … | + | ||
391 … | + cb(null, self.serveRedirect(req, req.url)) | ||
392 … | + }) | ||
393 … | + | ||
369 | 394 … | case 'new-issue': | |
370 | 395 … | var msg = Issues.schemas.new(dir, data.text) | |
371 | 396 … | var mentions = Mentions(data.text) | |
372 | 397 … | if (mentions.length) |
lib/forms.js | ||
---|---|---|
@@ -2,26 +2,27 @@ | ||
2 | 2 … | var u = require('./util') |
3 | 3 … | var forms = exports |
4 | 4 … | |
5 | 5 … | forms.post = function (req, repo, placeholder, rows) { |
6 | - return '<input type="radio" class="tab-radio" id="tab1" name="tab" checked="checked"/>' + | |
6 … | + return '<div class="post-form">' + | |
7 … | + '<input type="radio" class="tab-radio" id="tab1" name="tab" checked="checked"/>' + | |
7 | 8 … | '<input type="radio" class="tab-radio" id="tab2" name="tab"/>' + |
8 | 9 … | '<div id="tab-links" class="tab-links" style="display:none">' + |
9 | 10 … | '<label for="tab1" id="write-tab-link" class="tab1-link">' + |
10 | 11 … | req._t('post.Write') + '</label>' + |
11 | 12 … | '<label for="tab2" id="preview-tab-link" class="tab2-link">' + |
12 | 13 … | req._t('post.Preview') + '</label>' + |
13 | 14 … | '</div>' + |
14 | 15 … | (repo ? |
15 | - '<input type="hidden" id="repo-id" value="' + repo.id + '"/>' | |
16 … | + '<input type="hidden" id="repo-id" class="repo-id" value="' + repo.id + '"/>' | |
16 | 17 … | : '') + |
17 | 18 … | '<div id="write-tab" class="tab1">' + |
18 | - '<textarea id="post-text" name="text" class="wide-input"' + | |
19 … | + '<textarea id="post-text" class="post-text" name="text" class="wide-input"' + | |
19 | 20 … | ' rows="' + (rows||4) + '" cols="77"' + |
20 | 21 … | (placeholder ? ' placeholder="' + placeholder + '"' : '') + |
21 | 22 … | '></textarea>' + |
22 | 23 … | '</div>' + |
23 | - '<div class="preview-text tab2" id="preview-tab"></div>' + | |
24 … | + '<div class="preview-text tab2" id="preview-tab"></div></div>' + | |
24 | 25 … | '<script>' + issueCommentScript + '</script>' |
25 | 26 … | } |
26 | 27 … | |
27 | 28 … | forms.name = function (req, enabled, id, name, action, inputId, title, header) { |
@@ -53,19 +54,21 @@ | ||
53 | 54 … | ]) |
54 | 55 … | } |
55 | 56 … | |
56 | 57 … | var issueCommentScript = '(' + function () { |
57 | - var $ = document.getElementById.bind(document) | |
58 | - $('tab-links').style.display = 'block' | |
59 | - $('preview-tab-link').onclick = function (e) { | |
58 … | + var container = [].slice.call(document.querySelectorAll('.post-form')).pop() || document.body | |
59 … | + var $ = container.querySelector.bind(container) | |
60 … | + $('.tab-links').style.display = 'block' | |
61 … | + $('.tab2-link').onclick = function (e) { | |
60 | 62 … | with (new XMLHttpRequest()) { |
61 | 63 … | open('POST', '', true) |
62 | 64 … | onload = function() { |
63 | - $('preview-tab').innerHTML = responseText | |
65 … | + $('.preview-text').innerHTML = responseText | |
64 | 66 … | } |
67 … | + var repoInput = $('.repo-id') | |
65 | 68 … | send('action=markdown' + |
66 | - '&repo=' + encodeURIComponent($('repo-id').value) + | |
67 | - '&text=' + encodeURIComponent($('post-text').value)) | |
69 … | + (repoInput ? '&repo=' + encodeURIComponent(repoInput.value) : '') + | |
70 … | + '&text=' + encodeURIComponent($('.post-text').value)) | |
68 | 71 … | } |
69 | 72 … | } |
70 | 73 … | }.toString() + ')()' |
71 | 74 … | |
@@ -102,12 +105,12 @@ | ||
102 | 105 … | '<script>' + issueCommentButtonScript + '</script>' + |
103 | 106 … | '</form></section>' |
104 | 107 … | } |
105 | 108 … | |
106 | -forms.lineComment = function (req, repo, repoBranch, commitId, filePath, line) { | |
109 … | +forms.lineComment = function (req, repo, updateId, commitId, filePath, line) { | |
107 | 110 … | return '<section><form action="" method="post">' + |
108 | 111 … | '<input type="hidden" name="action" value="line-comment">' + |
109 | - '<input type="hidden" name="repoBranch" value="' + repoBranch.join(',') + '">' + | |
112 … | + '<input type="hidden" name="updateId" value="' + updateId + '">' + | |
110 | 113 … | '<input type="hidden" name="repo" value="' + repo.id + '">' + |
111 | 114 … | '<input type="hidden" name="commitId" value="' + commitId + '">' + |
112 | 115 … | '<input type="hidden" name="filePath" value="' + filePath + '">' + |
113 | 116 … | '<input type="hidden" name="line" value="' + line + '">' + |
@@ -115,4 +118,15 @@ | ||
115 | 118 … | '<input type="submit" class="btn open" value="' + |
116 | 119 … | req._t('issue.LineComment') + '" />' + |
117 | 120 … | '</form></section>' |
118 | 121 … | } |
122 … | + | |
123 … | +forms.lineCommentReply = function (req, root, branch) { | |
124 … | + return '<section><form action="" method="post">' + | |
125 … | + '<input type="hidden" name="action" value="line-comment-reply">' + | |
126 … | + '<input type="hidden" name="root" value="' + root + '">' + | |
127 … | + '<input type="hidden" name="branch" value="' + branch + '">' + | |
128 … | + forms.post(req) + | |
129 … | + '<input type="submit" class="btn open" value="' + | |
130 … | + req._t('Reply') + '" />' + | |
131 … | + '</form></section>' | |
132 … | +} |
lib/repos/index.js | ||
---|---|---|
@@ -14,8 +14,9 @@ | ||
14 | 14 … | var ssbRef = require('ssb-ref') |
15 | 15 … | var zlib = require('zlib') |
16 | 16 … | var toPull = require('stream-to-pull-stream') |
17 | 17 … | var h = require('pull-hyperscript') |
18 … | +var getObjectMsgId = require('../../lib/obj-msg-id') | |
18 | 19 … | |
19 | 20 … | function extend(obj, props) { |
20 | 21 … | for (var k in props) |
21 | 22 … | obj[k] = props[k] |
@@ -45,8 +46,115 @@ | ||
45 | 46 … | } |
46 | 47 … | |
47 | 48 … | /* Repo */ |
48 | 49 … | |
50 … | +R.getLineCommentThreads = function (req, repo, updateId, commitId, filename, cb) { | |
51 … | + var self = this | |
52 … | + var sbot = self.web.ssb | |
53 … | + var lineCommentThreads = {} | |
54 … | + pull( | |
55 … | + sbot.backlinks ? sbot.backlinks.read({ | |
56 … | + query: [ | |
57 … | + {$filter: { | |
58 … | + dest: updateId, | |
59 … | + value: { | |
60 … | + content: { | |
61 … | + type: 'line-comment', | |
62 … | + repo: repo.id, | |
63 … | + updateId: updateId, | |
64 … | + commitId: commitId, | |
65 … | + filePath: filename | |
66 … | + } | |
67 … | + } | |
68 … | + }} | |
69 … | + ] | |
70 … | + }) : pull( | |
71 … | + sbot.links({ | |
72 … | + dest: updateId, | |
73 … | + rel: 'updateId', | |
74 … | + values: true | |
75 … | + }), | |
76 … | + pull.filter(function (msg) { | |
77 … | + var c = msg && msg.value && msg.value.content | |
78 … | + return c && c.type === 'line-comment' | |
79 … | + && c.updateId === updateId | |
80 … | + && c.commitId === commitId | |
81 … | + && c.filePath === filename | |
82 … | + }) | |
83 … | + ), | |
84 … | + paramap(function (msg, cb) { | |
85 … | + pull( | |
86 … | + self.renderThread(req, repo, msg), | |
87 … | + pull.collect(function (err, parts) { | |
88 … | + if (err) return cb(err) | |
89 … | + cb(null, { | |
90 … | + line: msg.value.content.line, | |
91 … | + html: parts.join(''), | |
92 … | + }) | |
93 … | + }) | |
94 … | + ) | |
95 … | + }, 4), | |
96 … | + pull.drain(function (thread) { | |
97 … | + lineCommentThreads[thread.line] = thread.html | |
98 … | + }, function (err) { | |
99 … | + if (err) return cb(err) | |
100 … | + cb(null, lineCommentThreads) | |
101 … | + }) | |
102 … | + ) | |
103 … | +} | |
104 … | + | |
105 … | +R.renderThread = function (req, repo, msg) { | |
106 … | + var newestMsg = msg | |
107 … | + var root = msg.key | |
108 … | + var self = this | |
109 … | + return h('div', [ | |
110 … | + pull( | |
111 … | + cat([ | |
112 … | + pull.once(msg), | |
113 … | + self.web.ssb.links({ | |
114 … | + dest: root, | |
115 … | + values: true | |
116 … | + }), | |
117 … | + ]), | |
118 … | + pull.unique('key'), | |
119 … | + u.decryptMessages(self.web.ssb), | |
120 … | + u.readableMessages(), | |
121 … | + self.web.addAuthorName(), | |
122 … | + u.sortMsgs(), | |
123 … | + pull.filter(function (msg) { | |
124 … | + var c = msg && msg.value && msg.value.content | |
125 … | + return c && (c.type === 'post' | |
126 … | + || msg.key === root) | |
127 … | + }), | |
128 … | + pull.through(function (msg) { | |
129 … | + // TODO: correctly calculate the thread branches | |
130 … | + if (msg.value | |
131 … | + && msg.value.timestamp > newestMsg.value.timestamp) | |
132 … | + newestMsg = msg | |
133 … | + }), | |
134 … | + pull.map(function (msg) { | |
135 … | + return self.renderLineComment(req, repo, msg) | |
136 … | + }) | |
137 … | + ), | |
138 … | + self.web.isPublic ? '' : | |
139 … | + pull.once(forms.lineCommentReply(req, root, newestMsg.key)) | |
140 … | + ]) | |
141 … | +} | |
142 … | + | |
143 … | +R.renderLineComment = function (req, repo, msg) { | |
144 … | + var c = msg && msg.value && msg.value.content | |
145 … | + return h('section', {class: 'collapse'}, [ | |
146 … | + h('div', [ | |
147 … | + u.link([msg.value.author], msg.authorName), | |
148 … | + ' ', | |
149 … | + h('tt', {class: 'right-bar item-id'}, msg.key), | |
150 … | + ' · ', | |
151 … | + h('a', {href: u.encodeLink(msg.key) + '#' + encodeURIComponent(msg.key)}, new Date(msg.value.timestamp).toLocaleString(req._locale)), | |
152 … | + ]), | |
153 … | + markdown(c.text, repo) | |
154 … | + ]) | |
155 … | +} | |
156 … | + | |
49 | 157 … | R.serveRepoPage = function (req, repo, path) { |
50 | 158 … | var self = this |
51 | 159 … | var defaultBranch = 'master' |
52 | 160 … | var query = req._u.query |
@@ -593,46 +701,50 @@ | ||
593 | 701 … | /* Repo commit */ |
594 | 702 … | |
595 | 703 … | R.serveRepoCommit = function (req, repo, rev) { |
596 | 704 … | var self = this |
597 | - var repoBranch = [] | |
598 | 705 … | return u.readNext(function (cb) { |
599 | 706 … | repo.getCommitParsed(rev, function (err, commit) { |
600 | 707 … | if (err) return cb(null, |
601 | 708 … | self.serveRepoTemplate(req, repo, null, rev, `%{author}/%{repo}@${rev}`, |
602 | 709 … | pull.once(self.web.renderError(err)))) |
603 | - var commitPath = [repo.id, 'commit', commit.id] | |
604 | - var treePath = [repo.id, 'tree', commit.id] | |
605 | - var title = u.escape(commit.title) + ' · ' + | |
606 | - '%{author}/%{repo}@' + commit.id.substr(0, 8) | |
607 | - cb(null, self.serveRepoTemplate(req, repo, null, rev, title, cat([ | |
608 | - pull.once( | |
609 | - '<h3>' + u.link(commitPath, | |
610 | - req._t('CommitRev', {rev: rev})) + '</h3>' + | |
611 | - '<section class="collapse">' + | |
612 | - '<div class="right-bar">' + | |
613 | - u.link(treePath, req._t('BrowseFiles')) + | |
614 | - '</div>' + | |
615 | - '<h4>' + u.linkify(u.escape(commit.title)) + '</h4>' + | |
616 | - (commit.body ? u.linkify(u.pre(commit.body)) : '') + | |
617 | - (commit.separateAuthor ? req._t('AuthoredOn', { | |
618 | - name: u.escape(commit.author.name), | |
619 | - date: commit.author.date.toLocaleString(req._locale) | |
620 | - }) + '<br/>' : '') + | |
621 | - req._t('CommittedOn', { | |
622 | - name: u.escape(commit.committer.name), | |
623 | - date: commit.committer.date.toLocaleString(req._locale) | |
624 | - }) + '<br/>' + | |
625 | - commit.parents.map(function (id) { | |
626 | - return req._t('Parent') + ': ' + | |
627 | - u.link([repo.id, 'commit', id], id) | |
628 | - }).join('<br>') + | |
629 | - '</section>' + | |
630 | - '<section><h3>' + req._t('FilesChanged') + '</h3>'), | |
631 | - // TODO: show diff from all parents (merge commits) | |
632 | - self.renderDiffStat(req, [repo, repo], [commit.parents[0], commit.id], commit.id, repoBranch), | |
633 | - pull.once('</section>') | |
634 | - ]))) | |
710 … | + getObjectMsgId(repo, commit.id, function (err, objMsgId) { | |
711 … | + if (err) return cb(null, | |
712 … | + self.serveRepoTemplate(req, repo, null, rev, `%{author}/%{repo}@${rev}`, | |
713 … | + pull.once(self.web.renderError(err)))) | |
714 … | + var commitPath = [repo.id, 'commit', commit.id] | |
715 … | + var treePath = [repo.id, 'tree', commit.id] | |
716 … | + var title = u.escape(commit.title) + ' · ' + | |
717 … | + '%{author}/%{repo}@' + commit.id.substr(0, 8) | |
718 … | + cb(null, self.serveRepoTemplate(req, repo, null, rev, title, cat([ | |
719 … | + pull.once( | |
720 … | + '<h3>' + u.link(commitPath, | |
721 … | + req._t('CommitRev', {rev: rev})) + '</h3>' + | |
722 … | + '<section class="collapse">' + | |
723 … | + '<div class="right-bar">' + | |
724 … | + u.link(treePath, req._t('BrowseFiles')) + | |
725 … | + '</div>' + | |
726 … | + '<h4>' + u.linkify(u.escape(commit.title)) + '</h4>' + | |
727 … | + (commit.body ? u.linkify(u.pre(commit.body)) : '') + | |
728 … | + (commit.separateAuthor ? req._t('AuthoredOn', { | |
729 … | + name: u.escape(commit.author.name), | |
730 … | + date: commit.author.date.toLocaleString(req._locale) | |
731 … | + }) + '<br/>' : '') + | |
732 … | + req._t('CommittedOn', { | |
733 … | + name: u.escape(commit.committer.name), | |
734 … | + date: commit.committer.date.toLocaleString(req._locale) | |
735 … | + }) + '<br/>' + | |
736 … | + commit.parents.map(function (id) { | |
737 … | + return req._t('Parent') + ': ' + | |
738 … | + u.link([repo.id, 'commit', id], id) | |
739 … | + }).join('<br>') + | |
740 … | + '</section>' + | |
741 … | + '<section><h3>' + req._t('FilesChanged') + '</h3>'), | |
742 … | + // TODO: show diff from all parents (merge commits) | |
743 … | + self.renderDiffStat(req, [repo, repo], [commit.parents[0], commit.id], commit.id, objMsgId), | |
744 … | + pull.once('</section>') | |
745 … | + ]))) | |
746 … | + }) | |
635 | 747 … | }) |
636 | 748 … | }) |
637 | 749 … | } |
638 | 750 … | |
@@ -673,9 +785,10 @@ | ||
673 | 785 … | |
674 | 786 … | |
675 | 787 … | /* Diff stat */ |
676 | 788 … | |
677 | -R.renderDiffStat = function (req, repos, treeIds, commit, repoBranch) { | |
789 … | +R.renderDiffStat = function (req, repos, treeIds, commit, updateId) { | |
790 … | + var self = this | |
678 | 791 … | if (treeIds.length == 0) treeIds = [null] |
679 | 792 … | var id = treeIds[0] |
680 | 793 … | var lastI = treeIds.length - 1 |
681 | 794 … | var oldTree = treeIds[0] |
@@ -734,25 +847,26 @@ | ||
734 | 847 … | var done = multicb({ pluck: 1, spread: true }) |
735 | 848 … | var mode0 = item.mode && item.mode[0] |
736 | 849 … | var modeI = item.mode && item.mode[lastI] |
737 | 850 … | var isSubmodule = (modeI == 0160000) |
851 … | + var repo = repos[1] | |
738 | 852 … | getRepoObjectString(repos[0], item.id[0], mode0, done()) |
739 | 853 … | getRepoObjectString(repos[1], item.id[lastI], modeI, done()) |
740 | - done(function (err, strOld, strNew) { | |
854 … | + self.getLineCommentThreads(req, repo, updateId, commit, item.filename, done()) | |
855 … | + done(function (err, strOld, strNew, lineCommentThreads) { | |
741 | 856 … | if (err) return cb(err) |
742 | - var repo = repos[1] | |
743 | - cb(null, htmlLineDiff(req, repo, repoBranch, commit, item.filename, item.filename, | |
857 … | + cb(null, htmlLineDiff(req, repo, updateId, commit, item.filename, item.filename, | |
744 | 858 … | strOld, strNew, |
745 | - u.encodeLink(item.blobPath), !isSubmodule)) | |
859 … | + u.encodeLink(item.blobPath), !isSubmodule, lineCommentThreads)) | |
746 | 860 … | }) |
747 | 861 … | }, 4) |
748 | 862 … | ) |
749 | 863 … | ]) |
750 | 864 … | } |
751 | 865 … | |
752 | -function htmlLineDiff(req, repo, repoBranch, commit, filename, anchor, oldStr, newStr, blobHref, | |
753 | - showViewLink) { | |
754 | - return '<pre><table class="code">' + | |
866 … | +function htmlLineDiff(req, repo, updateId, commit, filename, anchor, oldStr, newStr, blobHref, | |
867 … | + showViewLink, lineCommentThreads) { | |
868 … | + return '<div class="code-wrap"><table class="code">' + | |
755 | 869 … | '<tr><th colspan=3 id="' + u.escape(anchor) + '">' + filename + |
756 | 870 … | (showViewLink === false ? '' : |
757 | 871 … | '<span class="right-bar">' + |
758 | 872 … | '<a href="' + blobHref + '">' + req._t('View') + '</a> ' + |
@@ -761,13 +875,13 @@ | ||
761 | 875 … | (oldStr.length + newStr.length > 200000 |
762 | 876 … | ? '<tr><td class="diff-info" colspan=3>' + req._t('diff.TooLarge') + '<br>' + |
763 | 877 … | req._t('diff.OldFileSize', {bytes: oldStr.length}) + '<br>' + |
764 | 878 … | req._t('diff.NewFileSize', {bytes: newStr.length}) + '</td></tr>' |
765 | - : tableDiff(req, repo, repoBranch, commit, oldStr, newStr, filename)) + | |
766 | - '</table></pre>' | |
879 … | + : tableDiff(req, repo, updateId, commit, oldStr, newStr, filename, lineCommentThreads)) + | |
880 … | + '</table></div>' | |
767 | 881 … | } |
768 | 882 … | |
769 | -function tableDiff(req, repo, repoBranch, commit, oldStr, newStr, filename) { | |
883 … | +function tableDiff(req, repo, updateId, commit, oldStr, newStr, filename, lineCommentThreads) { | |
770 | 884 … | var query = req._u.query |
771 | 885 … | var diff = JsDiff.structuredPatch('', '', oldStr, newStr) |
772 | 886 … | var groups = diff.hunks.map(function (hunk) { |
773 | 887 … | var oldLine = hunk.oldStart |
@@ -782,25 +896,31 @@ | ||
782 | 896 … | var html = u.highlight(line, u.getExtension(filename)) |
783 | 897 … | var trClass = s == '+' ? 'diff-new' : s == '-' ? 'diff-old' : '' |
784 | 898 … | var lineNums = [s == '+' ? '' : oldLine++, s == '-' ? '' : newLine++] |
785 | 899 … | var id = [filename].concat(lineNums).join('-') |
900 … | + var newLineNum = lineNums[lineNums.length-1] | |
786 | 901 … | return '<tr id="' + u.escape(id) + '" class="' + trClass + '">' + |
787 | 902 … | lineNums.map(function (num, i) { |
788 | 903 … | var idEnc = encodeURIComponent(id) |
789 | 904 … | return '<td class="code-linenum">' + |
790 | 905 … | (num ? '<a href="#' + idEnc + '">' + |
791 | 906 … | num + '</a>' + |
792 | - (i === lineNums.length-1 && s !== '-' ? | |
907 … | + (updateId && i === lineNums.length-1 && s !== '-' ? | |
793 | 908 … | // TODO: use a more descriptive icon for the comment action |
794 | 909 … | ' <a href="?comment=' + idEnc + '#' + idEnc + '">…</a>' |
795 | 910 … | : '') |
796 | 911 … | : '') + '</td>' |
797 | 912 … | }).join('') + |
798 | 913 … | '<td class="code-text">' + html + '</td></tr>' + |
799 | 914 … | (commit && query.comment === id ? |
800 | 915 … | '<tr><td colspan=4>' + |
801 | - forms.lineComment(req, repo, repoBranch, commit, filename, lineNums[lineNums.length-1]) + | |
916 … | + forms.lineComment(req, repo, updateId, commit, filename, newLineNum) + | |
802 | 917 … | '</td></tr>' |
918 … | + : '') + | |
919 … | + (lineCommentThreads[newLineNum] ? | |
920 … | + '<tr><td colspan=4>' + | |
921 … | + lineCommentThreads[newLineNum] + | |
922 … | + '</td></tr>' | |
803 | 923 … | : '') |
804 | 924 … | })) |
805 | 925 … | }) |
806 | 926 … | return [].concat.apply([], groups).join('') |
lib/repos/pulls.js | ||
---|---|---|
@@ -7,8 +7,9 @@ | ||
7 | 7 … | var u = require('../../lib/util') |
8 | 8 … | var markdown = require('../../lib/markdown') |
9 | 9 … | var forms = require('../../lib/forms') |
10 | 10 … | var ssbRef = require('ssb-ref') |
11 … | +var getObjectMsgId = require('../../lib/obj-msg-id') | |
11 | 12 … | |
12 | 13 … | module.exports = function (repoRoutes, web) { |
13 | 14 … | return new RepoPullReqRoutes(repoRoutes, web) |
14 | 15 … | } |
@@ -112,16 +113,18 @@ | ||
112 | 113 … | if (!revs.head) return cb(null, pull.once('<section>' + |
113 | 114 … | req._t('pullRequest.NoChanges') + '</section>')) |
114 | 115 … | GitRepo.getMergeBase(baseRepo, revs.base, headRepo, revs.head, |
115 | 116 … | function (err, mergeBase) { |
116 | - var repoBranch = [] | |
117 | 117 … | if (err) return cb(err) |
118 | - cb(null, cat([ | |
119 | - pull.once('<section>'), | |
120 | - self.repo.renderDiffStat(req, | |
121 | - [baseRepo, headRepo], [mergeBase, revs.head], revs.head, repoBranch), | |
122 | - pull.once('</section>') | |
123 | - ])) | |
118 … | + getObjectMsgId(headRepo, revs.head, function (err, objMsgId) { | |
119 … | + if (err) return cb(err) | |
120 … | + cb(null, cat([ | |
121 … | + pull.once('<section>'), | |
122 … | + self.repo.renderDiffStat(req, | |
123 … | + [baseRepo, headRepo], [mergeBase, revs.head], revs.head, objMsgId), | |
124 … | + pull.once('</section>') | |
125 … | + ])) | |
126 … | + }) | |
124 | 127 … | } |
125 | 128 … | ) |
126 | 129 … | }) |
127 | 130 … | } |
locale/en.json | ||
---|---|---|
@@ -136,8 +136,9 @@ | ||
136 | 136 … | "CommentAndClose": "Comment and Close", |
137 | 137 … | "Reopen": "Reopen %{type}", |
138 | 138 … | "CommentAndReopen": "Comment and Reopen" |
139 | 139 … | }, |
140 … | + "Reply": "Reply", | |
140 | 141 … | "pullRequest": { |
141 | 142 … | "WantToMerge": "%{name} wants to merge commits into %{base} from %{head}", |
142 | 143 … | "Discussion": "Discussion", |
143 | 144 … | "New": "New Pull Request", |
locale/eo.json | ||
---|---|---|
@@ -136,8 +136,9 @@ | ||
136 | 136 … | "CommentAndClose": "Komenti kaj Fermi", |
137 | 137 … | "Reopen": "Remalfermi %{type}", |
138 | 138 … | "CommandAndReopen": "Komenti kaj Remalfermi" |
139 | 139 … | }, |
140 … | + "Reply": "Reply", | |
140 | 141 … | "pullRequest": { |
141 | 142 … | "WantToMerge": "%{name} volas kunfandi enmetoj en %{base} de %{head}", |
142 | 143 … | "Discussion": "Priparolado", |
143 | 144 … | "New": "Nova Tiro-peto", |
schemas.md | ||
---|---|---|
@@ -4,14 +4,14 @@ | ||
4 | 4 … | { |
5 | 5 … | "type": "line-comment", |
6 | 6 … | "text": string, |
7 | 7 … | "repo": MsgId, |
8 | - "repoBranch": MgsIds, | |
8 … | + "updateId": MgsIds, | |
9 | 9 … | "line": number, |
10 | 10 … | } |
11 | 11 … | ``` |
12 | 12 … | `repo`: id of `git-repo` |
13 | -`repoBranch`: id(s) of `git-update` messages that pushed the git commit, git trees, and git blobs needed to render the diff. | |
13 … | +`updateId`: id of a `git-update` message that pushed the git commit, git trees, and git blobs needed to render the diff. | |
14 | 14 … | `commitId`: commit that the comment is on |
15 | 15 … | `filePath`: path to the file that the comment is on |
16 | 16 … | `line`: line number of the file that the comment is on |
17 | 17 … |
static/styles.css | ||
---|---|---|
@@ -17,8 +17,21 @@ | ||
17 | 17 … | margin-left: auto; |
18 | 18 … | margin-right: auto; |
19 | 19 … | } |
20 | 20 … | |
21 … | +.code-wrap { | |
22 … | + padding: .5em 1.25ex; | |
23 … | + border: 1px solid #ddd; | |
24 … | + background: #f5f5f5; | |
25 … | +} | |
26 … | + | |
27 … | +.diff-hunk-header, | |
28 … | +.code-linenum, | |
29 … | +.code-text { | |
30 … | + font: .8em Consolas, "Liberation Mono", Menlo, Courier, monospace; | |
31 … | + white-space: pre-wrap; | |
32 … | +} | |
33 … | + | |
21 | 34 … | pre { |
22 | 35 … | font: .8em Consolas, "Liberation Mono", Menlo, Courier, monospace; |
23 | 36 … | padding: .5em 1.25ex; |
24 | 37 … | border: 1px solid #ddd; |
@@ -31,8 +44,9 @@ | ||
31 | 44 … | border-radius: .5ex; |
32 | 45 … | background-color: #fff; |
33 | 46 … | } |
34 | 47 … | |
48 … | +.code-wrap > code, | |
35 | 49 … | pre > code { |
36 | 50 … | padding: 0; |
37 | 51 … | background-color: #f5f5f5; |
38 | 52 … | } |
Built with git-ssb-web