From cbf9a1d87eb43eaea73e6c019e7b4a2dca3bbaa6 Mon Sep 17 00:00:00 2001 From: cel Date: Mon, 8 Jan 2018 19:11:15 -1000 Subject: Render line-comment messages --- lib/render-msg.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'lib/render-msg.js') diff --git a/lib/render-msg.js b/lib/render-msg.js index d4ad670..0835fee 100644 --- a/lib/render-msg.js +++ b/lib/render-msg.js @@ -10,6 +10,7 @@ function RenderMsg(render, app, msg, opts) { this.render = render this.app = app this.msg = msg + this.serve = opts.serve this.value = msg && msg.value || {} var content = this.value.content this.c = content || {} @@ -20,6 +21,13 @@ function RenderMsg(render, app, msg, opts) { this.shouldWrap = this.opts.wrap !== false } +RenderMsg.prototype.getMsg = function (id, cb) { + if (!id) return cb() + return this.serve + ? this.serve.getMsgDecryptedMaybeOoo(id, cb) + : this.app.getMsgDecryptedOoo(id, cb) +} + RenderMsg.prototype.toUrl = function (href) { return this.render.toUrl(href) } @@ -287,6 +295,7 @@ RenderMsg.prototype.message = function (cb) { case 'talenet-idea-comment': case 'talenet-idea-comment_reply': return this.ideaComment(cb) case 'about-resource': return this.aboutResource(cb) + case 'line-comment': return this.lineComment(cb) default: return this.object(cb) } } @@ -1638,3 +1647,30 @@ RenderMsg.prototype.aboutResource = function (cb) { h('blockquote', {innerHTML: self.render.markdown(self.c.description)}) ), cb) } + +RenderMsg.prototype.lineComment = function (cb) { + var self = this + var done = multicb({pluck: 1, spread: true}) + self.link(self.c.repo, done()) + self.getMsg(self.c.updateId, done()) + done(function (err, repoLink, updateMsg) { + if (err) return cb(err) + return self.wrap(h('div', + h('div', h('small', '> ', + repoLink, ' ', + h('a', { + href: self.toUrl(self.c.updateId) + }, + updateMsg + ? htime(new Date(updateMsg.value.timestamp)) + : String(self.c.updateId) + ), ' ', + h('a', { + href: self.toUrl('/git/commit/' + self.c.commitId + '?msg=' + encodeURIComponent(self.c.updateId)) + }, String(self.c.commitId).substr(0, 8)), ' ', + h('code', self.c.filePath + ':' + self.c.line) + )), + self.c.text ? + h('div', {innerHTML: self.render.markdown(self.c.text)}) : ''), cb) + }) +} -- cgit v1.2.3 From 09cf04663fe2a772d5a06bbcf86b9014dc4f5228 Mon Sep 17 00:00:00 2001 From: cel Date: Mon, 8 Jan 2018 22:03:51 -1000 Subject: Render line comments on diffs --- lib/app.js | 75 ++++++++++++++++++++++++++++++ lib/render-msg.js | 5 +- lib/serve.js | 133 ++++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 174 insertions(+), 39 deletions(-) (limited to 'lib/render-msg.js') diff --git a/lib/app.js b/lib/app.js index 21f45a4..9166eb2 100644 --- a/lib/app.js +++ b/lib/app.js @@ -905,3 +905,78 @@ App.prototype.expandOoo = function (opts, cb) { } } } + +App.prototype.getLineComments = function (opts, cb) { + // get line comments for a git-update message and git object id. + // line comments include message id, commit id and path + // but we have message id and git object hash. + // look up the git object hash for each line-comment + // to verify that it is for the git object file we want + var updateId = opts.obj.msg.key + var objId = opts.hash + var self = this + var lineComments = {} + pull( + self.sbot.backlinks ? self.sbot.backlinks.read({ + query: [ + {$filter: { + dest: updateId, + value: { + content: { + type: 'line-comment', + updateId: updateId, + } + } + }} + ] + }) : pull( + self.sbot.links({ + dest: updateId, + rel: 'updateId', + values: true + }), + pull.filter(function (msg) { + var c = msg && msg.value && msg.value.content + return c && c.type === 'line-comment' + && c.updateId === updateId + }) + ), + paramap(function (msg, cb) { + var c = msg.value.content + self.git.getObjectAtPath({ + msg: updateId, + obj: c.commitId, + path: c.filePath, + }, function (err, info) { + if (err) return cb(err) + cb(null, { + obj: info.obj, + hash: info.hash, + msg: msg, + }) + }) + }, 4), + pull.filter(function (info) { + return info.hash === objId + }), + pull.drain(function (info) { + lineComments[info.msg.value.content.line] = info + }, function (err) { + cb(err, lineComments) + }) + ) +} + +App.prototype.getThread = function (msg) { + return cat([ + pull.once(msg), + this.sbot.backlinks ? this.sbot.backlinks.read({ + query: [ + {$filter: {dest: msg.key}} + ] + }) : this.sbot.links({ + dest: msg.key, + values: true + }) + ]) +} diff --git a/lib/render-msg.js b/lib/render-msg.js index 0835fee..78c7d5c 100644 --- a/lib/render-msg.js +++ b/lib/render-msg.js @@ -1668,7 +1668,10 @@ RenderMsg.prototype.lineComment = function (cb) { h('a', { href: self.toUrl('/git/commit/' + self.c.commitId + '?msg=' + encodeURIComponent(self.c.updateId)) }, String(self.c.commitId).substr(0, 8)), ' ', - h('code', self.c.filePath + ':' + self.c.line) + h('a', { + href: self.toUrl('/git/line-comment/' + + encodeURIComponent(self.msg.key)) + }, h('code', self.c.filePath + ':' + self.c.line)) )), self.c.text ? h('div', {innerHTML: self.render.markdown(self.c.text)}) : ''), cb) diff --git a/lib/serve.js b/lib/serve.js index f191b77..78ff104 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -1651,6 +1651,7 @@ Serve.prototype.git = function (url) { case 'blob': return this.gitBlob(m[2]) case 'raw': return this.gitRaw(m[2]) case 'diff': return this.gitDiff(m[2]) + case 'line-comment': return this.gitLineComment(m[2]) default: return this.respond(404, 'Not found') } } @@ -2114,12 +2115,16 @@ Serve.prototype.gitDiff = function (revs) { var done = multicb({pluck: 1, spread: true}) pull.collect(done())(self.app.git.readObject(obj1)) pull.collect(done())(self.app.git.readObject(obj2)) - done(function (err, bufs1, bufs2) { + self.app.getLineComments({obj: obj2, hash: rev2}, done()) + done(function (err, bufs1, bufs2, lineComments) { if (err) return cb(err) var str1 = Buffer.concat(bufs1, obj1.length).toString('utf8') var str2 = Buffer.concat(bufs2, obj2.length).toString('utf8') var diff = Diff.structuredPatch('', '', str1, str2) - cb(null, self.gitDiffTable(diff)) + cb(null, self.gitDiffTable(diff, lineComments, { + obj: obj2, + hash: rev2, + })) }) }) }) @@ -2130,12 +2135,10 @@ Serve.prototype.gitDiff = function (revs) { }) } -Serve.prototype.gitDiffTable = function (diff) { +Serve.prototype.gitDiffTable = function (diff, lineComments, lineCommentInfo) { var self = this return pull( ph('table', [ - ph('tr', [ - ]), pull( pull.values(diff.hunks), pull.map(function (hunk) { @@ -2157,39 +2160,42 @@ Serve.prototype.gitDiffTable = function (diff) { var lineNums = [s == '+' ? '' : oldLine++, s == '-' ? '' : newLine++] // var id = [filename].concat(lineNums).join('-') var newLineNum = lineNums[lineNums.length-1] - return ph('tr', { - class: s == '+' ? 'diff-new' : s == '-' ? 'diff-old' : '' - }, [ - lineNums.map(function (num, i) { - return ph('td', String(num)) - // TODO: allow linking to comments - /* - var idEnc = encodeURIComponent(id) - return '' + - (num ? '' + - num + '' + - (updateId && i === lineNums.length-1 && s !== '-' ? - ' ' - : '') - : '') + '' - } - */ - }), - ph('td', ph('pre', u.escapeHTML(html))) - ]) - - // TODO: line-comments - /* - (lineCommentThreads[newLineNum] ? - '' + - lineCommentThreads[newLineNum] + - '' - : commit && query.comment === id ? - '' + - forms.lineComment(req, repo, updateId, commit, filename, newLineNum) + - '' - : '') - */ + return [ + ph('tr', { + class: s == '+' ? 'diff-new' : s == '-' ? 'diff-old' : '' + }, [ + lineNums.map(function (num, i) { + return ph('td', String(num)) + // TODO: allow linking to comments + /* + var idEnc = encodeURIComponent(id) + return '' + + (num ? '' + + num + '' + + (updateId && i === lineNums.length-1 && s !== '-' ? + ' ' + : '') + : '') + '' + } + */ + }), + ph('td', ph('pre', u.escapeHTML(html))) + ]), + (lineComments[newLineNum] ? + ph('tr', + ph('td', {colspan: 4}, + self.renderLineCommentThread(lineComments[newLineNum]) + ) + ) + : /*commit && query.comment === id ? + ph('tr', + ph('td', {colspan: 4}, + // self.renderLineCommentForm(req, repo, updateId, commit, filename, newLineNum) + self.renderLineCommentForm(lineCommentInfo) + ) + ) + :*/ '') + ] }) ) ] @@ -2199,6 +2205,57 @@ Serve.prototype.gitDiffTable = function (diff) { ) } +Serve.prototype.renderLineCommentThread = function (lineComment) { + var self = this + return ph('table', {class: 'ssb-msgs'}, pull( + this.app.getThread(lineComment.msg), + self.renderThread() + )) +} + +Serve.prototype.renderLineCommentForm = function (info) { + var obj = info.obj + var hash = info.hash + return ph('pre', JSON.stringify(info, 0, 2)) +} + +Serve.prototype.gitLineComment = function (path) { + var self = this + var id = decodeURIComponent(String(path)) + self.getMsgDecryptedMaybeOoo(id, function (err, msg) { + if (err) return pull( + pull.once(u.renderError(err).outerHTML), + self.respondSink(400, {'Content-Type': ctype('html')}) + ) + var c = msg && msg.value && msg.value.content + if (!c) return pull( + pull.once('Missing message ' + id), + self.respondSink(500, {'Content-Type': ctype('html')}) + ) + self.app.git.getObjectAtPath({ + msg: c.updateId, + obj: c.commitId, + path: c.filePath, + }, function (err, obj) { + if (err && err.name === 'BlobNotFoundError') + return self.askWantBlobs(err.links) + if (err) return pull( + pull.once(err.stack), + self.respondSink(400, {'Content-Type': 'text/plain'}) + ) + + self.redirect(self.app.render.toUrl(publishedMsg.key)) + + /* + pull( + ph('pre', JSON.stringify(obj, 0, 2)), + self.respondSink(200) + ) + */ + }) + }) +} + Serve.prototype.gitObjectLinks = function (headMsgId, type) { var self = this return paramap(function (id, cb) { -- cgit v1.2.3 From 3c8e69899bcd403ed82bee2599bdd592150e5956 Mon Sep 17 00:00:00 2001 From: cel Date: Tue, 9 Jan 2018 19:04:39 -1000 Subject: Render line-comments and diffs better --- lib/render-msg.js | 2 +- lib/serve.js | 145 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 106 insertions(+), 41 deletions(-) (limited to 'lib/render-msg.js') diff --git a/lib/render-msg.js b/lib/render-msg.js index 78c7d5c..1603d24 100644 --- a/lib/render-msg.js +++ b/lib/render-msg.js @@ -1670,7 +1670,7 @@ RenderMsg.prototype.lineComment = function (cb) { }, String(self.c.commitId).substr(0, 8)), ' ', h('a', { href: self.toUrl('/git/line-comment/' + - encodeURIComponent(self.msg.key)) + encodeURIComponent(self.msg.key || JSON.stringify(self.msg))) }, h('code', self.c.filePath + ':' + self.c.line)) )), self.c.text ? diff --git a/lib/serve.js b/lib/serve.js index 6c8941c..6e3b451 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -1790,7 +1790,7 @@ Serve.prototype.gitCommit = function (rev) { : file.created ? ph('a', {href: self.app.render.toUrl('/git/blob/' - + file.hash[0] + + (file.hash[1] || file.hash[0]) + '?msg=' + encodeURIComponent(obj.msg.key)) }, 'created') : file.hash ? @@ -1798,6 +1798,8 @@ Serve.prototype.gitCommit = function (rev) { self.app.render.toUrl('/git/diff/' + file.hash[0] + '..' + file.hash[1] + '?msg=' + encodeURIComponent(obj.msg.key)) + + '&commit=' + rev + + '&path=' + encodeURIComponent(file.name) }, 'changed') : file.mode ? 'mode changed' : JSON.stringify(file)) @@ -2107,7 +2109,13 @@ Serve.prototype.gitDiff = function (revs) { obj: rev2, msg: msg2.key, }, done()) - done(function (err, obj1, obj2) { + /* + self.app.git.guessCommitAndPath({ + obj: rev2, + msg: msg2.key, + }, done()) + */ + done(function (err, obj1, obj2/*, info2*/) { if (err && err.name === 'BlobNotFoundError') return cb(null, self.askWantBlobsForm(err.links)) if (err) return cb(err) @@ -2124,6 +2132,8 @@ Serve.prototype.gitDiff = function (revs) { cb(null, self.gitDiffTable(diff, lineComments, { obj: obj2, hash: rev2, + commit: self.query.commit, // info2.commit, + path: self.query.path, // info2.path, })) }) }) @@ -2136,6 +2146,7 @@ Serve.prototype.gitDiff = function (revs) { } Serve.prototype.gitDiffTable = function (diff, lineComments, lineCommentInfo) { + var updateMsg = lineCommentInfo.obj.msg var self = this return pull( ph('table', [ @@ -2146,7 +2157,7 @@ Serve.prototype.gitDiffTable = function (diff, lineComments, lineCommentInfo) { var newLine = hunk.newStart return [ ph('tr', [ - ph('td', {colspan: 2}), + ph('td', {colspan: 3}), ph('td', ph('pre', '@@ -' + oldLine + ',' + hunk.oldLines + ' ' + '+' + newLine + ',' + hunk.newLines + ' @@')) @@ -2158,27 +2169,34 @@ Serve.prototype.gitDiffTable = function (diff, lineComments, lineCommentInfo) { if (s == '\\') return var html = self.app.render.highlight(line) var lineNums = [s == '+' ? '' : oldLine++, s == '-' ? '' : newLine++] - // var id = [filename].concat(lineNums).join('-') + var hash = lineCommentInfo.hash var newLineNum = lineNums[lineNums.length-1] + var id = hash + '-' + (newLineNum || (lineNums[0] + '-')) + var idEnc = encodeURIComponent(id) + var allowComment = s !== '-' + && self.query.commit && self.query.path return [ ph('tr', { class: s == '+' ? 'diff-new' : s == '-' ? 'diff-old' : '' }, [ lineNums.map(function (num, i) { - return ph('td', String(num)) - // TODO: allow linking to comments - /* - var idEnc = encodeURIComponent(id) - return '' + - (num ? '' + - num + '' + - (updateId && i === lineNums.length-1 && s !== '-' ? - ' ' - : '') - : '') + '' - } - */ + return ph('td', [ + ph('a', { + name: i === 0 ? idEnc : undefined, + href: '#' + idEnc + }, String(num)) + ]) }), + ph('td', + allowComment ? ph('a', { + href: '?msg=' + + encodeURIComponent(self.query.msg) + + '&comment=' + idEnc + + '&commit=' + encodeURIComponent(self.query.commit) + + '&path=' + encodeURIComponent(self.query.path) + + '#' + idEnc + }, '…') : '' + ), ph('td', ph('pre', u.escapeHTML(html))) ]), (lineComments[newLineNum] ? @@ -2187,14 +2205,20 @@ Serve.prototype.gitDiffTable = function (diff, lineComments, lineCommentInfo) { self.renderLineCommentThread(lineComments[newLineNum]) ) ) - : /*commit && query.comment === id ? + : newLineNum && lineCommentInfo && self.query.comment === id ? ph('tr', ph('td', {colspan: 4}, - // self.renderLineCommentForm(req, repo, updateId, commit, filename, newLineNum) - self.renderLineCommentForm(lineCommentInfo) + self.renderLineCommentForm({ + id: id, + line: newLineNum, + updateId: updateMsg.key, + repoId: updateMsg.value.content.repo, + commitId: lineCommentInfo.commit, + filePath: lineCommentInfo.path, + }) ) ) - :*/ '') + : '') ] }) ) @@ -2213,16 +2237,42 @@ Serve.prototype.renderLineCommentThread = function (lineComment) { )) } -Serve.prototype.renderLineCommentForm = function (info) { - var obj = info.obj - var hash = info.hash - return ph('pre', JSON.stringify(info, 0, 2)) +Serve.prototype.renderLineCommentForm = function (opts) { + return [ + this.phComposer({ + placeholder: 'comment on this line', + id: opts.id, + lineComment: opts + }) + ] +} + +// return a composer, pull-hyperscript style +Serve.prototype.phComposer = function (opts) { + var self = this + return u.readNext(function (cb) { + self.composer(opts, function (err, composer) { + if (err) return cb(err) + cb(null, pull.once(composer.outerHTML)) + }) + }) } Serve.prototype.gitLineComment = function (path) { var self = this - var id = decodeURIComponent(String(path)) - self.getMsgDecryptedMaybeOoo(id, function (err, msg) { + var id + try { + id = decodeURIComponent(String(path)) + if (id[0] === '%') { + return self.getMsgDecryptedMaybeOoo(id, gotMsg) + } else { + msg = JSON.parse(id) + } + } catch(e) { + return gotMsg(e) + } + gotMsg(null, msg) + function gotMsg(err, msg) { if (err) return pull( pull.once(u.renderError(err).outerHTML), self.respondSink(400, {'Content-Type': ctype('html')}) @@ -2232,28 +2282,35 @@ Serve.prototype.gitLineComment = function (path) { pull.once('Missing message ' + id), self.respondSink(500, {'Content-Type': ctype('html')}) ) - self.app.git.getObjectAtPath({ + self.app.git.diffFile({ msg: c.updateId, - obj: c.commitId, + commit: c.commitId, path: c.filePath, - }, function (err, obj) { + }, function (err, file) { if (err && err.name === 'BlobNotFoundError') return self.askWantBlobs(err.links) if (err) return pull( pull.once(err.stack), self.respondSink(400, {'Content-Type': 'text/plain'}) ) - - self.redirect(self.app.render.toUrl(publishedMsg.key)) - - /* - pull( - ph('pre', JSON.stringify(obj, 0, 2)), - self.respondSink(200) - ) - */ + var path + if (file.created) { + path = '/git/blob/' + file.hash[1] + + '?msg=' + encodeURIComponent(c.updateId) + + '&commit=' + c.commitId + + '&path=' + encodeURIComponent(c.filePath) + + '#' + file.hash[1] + '-' + c.line + } else { + path = '/git/diff/' + file.hash[0] + '..' + file.hash[1] + + '?msg=' + encodeURIComponent(c.updateId) + + '&commit=' + c.commitId + + '&path=' + encodeURIComponent(c.filePath) + + '#' + file.hash[1] + '-' + c.line + } + var url = self.app.render.toUrl(path) + self.redirect(url) }) - }) + } } Serve.prototype.gitObjectLinks = function (headMsgId, type) { @@ -2958,6 +3015,14 @@ Serve.prototype.composer = function (opts, cb) { type: 'post', text: String(data.text).replace(/\r\n/g, '\n'), } + if (opts.lineComment) { + content.type = 'line-comment' + content.updateId = opts.lineComment.updateId + content.repo = opts.lineComment.repoId + content.commitId = opts.lineComment.commitId + content.filePath = opts.lineComment.filePath + content.line = opts.lineComment.line + } var mentions = ssbMentions(data.text, {bareFeedNames: true, emoji: true}) .filter(function (mention) { if (mention.emoji) { -- cgit v1.2.3