Fix comments and rename 'reply all' to 'comment'

This changes some phrasing for clarity and adds some helpful
explanations when you're publishing a comment or a reply.

This also fixes comments on replies, which were previously just being
added as a sibling reply. This doesn't really matter because it has the
same layout in the UI and it's also very rare, but it allows us to have
separate threads for each reply.
This commit is contained in:
Christian Bundy 2019-12-28 16:30:49 -08:00
parent 0791880897
commit 826c90b8af
No known key found for this signature in database
GPG Key ID: EB541AAEF4366237
10 changed files with 92 additions and 60 deletions

View File

@ -33,7 +33,7 @@
- [ ] Posts
- [x] New
- [x] Reply
- [x] Reply all
- [x] Comment
- [ ] Pre-publish preview
- [ ] Add blob attachment(s)
- [x] Correctly set `branch`

View File

@ -23,9 +23,9 @@ const likesPage = require('./pages/likes')
const meta = require('./pages/meta')
const mentions = require('./pages/mentions')
const reply = require('./pages/reply')
const replyAll = require('./pages/reply-all')
const comment = require('./pages/comment')
const publishReply = require('./pages/publish-reply')
const publishReplyAll = require('./pages/publish-reply-all')
const publishComment = require('./pages/publish-comment')
const image = require('./pages/image')
const blob = require('./pages/blob')
const publish = require('./pages/publish')
@ -189,9 +189,9 @@ module.exports = (config) => {
const { message } = ctx.params
ctx.body = await reply(message)
})
.get('/reply-all/:message', async (ctx) => {
.get('/comment/:message', async (ctx) => {
const { message } = ctx.params
ctx.body = await replyAll(message)
ctx.body = await comment(message)
})
.post('/reply/:message', koaBody(), async (ctx) => {
const { message } = ctx.params
@ -199,10 +199,10 @@ module.exports = (config) => {
ctx.body = await publishReply({ message, text })
ctx.redirect(`/thread/${encodeURIComponent(message)}`)
})
.post('/reply-all/:message', koaBody(), async (ctx) => {
.post('/comment/:message', koaBody(), async (ctx) => {
const { message } = ctx.params
const text = String(ctx.request.body.text)
ctx.body = await publishReplyAll({ message, text })
ctx.body = await publishComment({ message, text })
ctx.redirect(`/thread/${encodeURIComponent(message)}`)
})
.post('/publish/', koaBody(), async (ctx) => {

26
src/pages/comment.js Normal file
View File

@ -0,0 +1,26 @@
'use strict'
const post = require('./models/post')
const meta = require('./models/meta')
const commentView = require('./views/comment')
const ssbRef = require('ssb-ref')
module.exports = async function commentPage (parentId) {
const parentMessage = await post.get(parentId)
const myFeedId = await meta.myFeedId()
const hasRoot = typeof parentMessage.value.content.root === 'string' && ssbRef.isMsg(parentMessage.value.content.root)
const hasFork = typeof parentMessage.value.content.fork === 'string' && ssbRef.isMsg(parentMessage.value.content.fork)
const rootMessage = hasRoot
? hasFork
? parentMessage
: await post.get(parentMessage.value.content.root)
: parentMessage
const messages = await post.threadReplies(rootMessage.key)
messages.push(rootMessage)
return commentView({ messages, myFeedId, parentMessage })
}

View File

@ -150,11 +150,15 @@ const transform = (ssb, messages, myFeedId) =>
url: avatarUrl
})
if (isRoot(msg)) {
const isPost = lodash.get(msg, 'value.content.type') === 'post' && lodash.get(msg, 'value.content.text') != null
const hasRoot = lodash.get(msg, 'value.content.root') != null
const hasFork = lodash.get(msg, 'value.content.fork') != null
if (isPost && hasRoot === false && hasFork === false) {
lodash.set(msg, 'value.meta.postType', 'post')
} else if (isReply(msg)) {
lodash.set(msg, 'value.meta.postType', 'replyAll')
} else if (isNestedReply(msg)) {
} else if (isPost && hasRoot && hasFork === false) {
lodash.set(msg, 'value.meta.postType', 'comment')
} else if (isPost && hasRoot && hasFork) {
lodash.set(msg, 'value.meta.postType', 'reply')
} else {
lodash.set(msg, 'value.meta.postType', 'mystery')
@ -232,7 +236,7 @@ const post = {
return messages
},
fromRoot: async (rootId, customOptions = {}) => {
threadReplies: async (rootId, customOptions = {}) => {
const ssb = await cooler.connect()
const myFeedId = ssb.id
@ -248,11 +252,11 @@ const post = {
customOptions,
ssb,
query,
filter: (msg) => msg.value.content.root === rootId
filter: (msg) =>
msg.value.content.root === rootId &&
msg.value.content.fork == null
})
console.log(messages)
return messages
},
likes: async ({ feed }, customOptions = {}) => {
@ -692,16 +696,23 @@ const post = {
return post.publish(message)
},
replyAll: async ({ parent, message }) => {
const fork = parent.key
const root = lodash.get(parent, 'value.content.root', parent.key)
message.root = fork || root
comment: async ({ parent, message }) => {
// Set `root` to `parent`'s root.
// If `parent` doesn't have a root, use the parent's key.
// If `parent` has a fork, you must use the parent's key.
const parentKey = parent.key
const parentFork = lodash.get(parent, 'value.content.fork')
const parentRoot = lodash.get(parent, 'value.content.root', parentKey)
const parentHasFork = parentFork != null
message.root = parentHasFork ? parentKey : parentRoot
message.branch = await post.branch({ root: parent.key })
message.type = 'post' // redundant but used for validation
if (isReply(message) !== true) {
const messageString = JSON.stringify(message, null, 2)
throw new Error(`message should be valid replyAll: ${messageString}`)
throw new Error(`message should be valid comment: ${messageString}`)
}
return post.publish(message)

View File

@ -4,14 +4,14 @@ const ssbMentions = require('ssb-mentions')
const post = require('./models/post')
const meta = require('./models/post')
module.exports = async function publishReplyAllPage ({ message, text }) {
module.exports = async function publishCommentPage ({ message, text }) {
// TODO: rename `message` to `parent` or `ancestor` or similar
const mentions = ssbMentions(text).filter((mention) =>
mention != null
) || undefined
const parent = await meta.get(message)
return post.replyAll({
return post.comment({
parent,
message: { text, mentions }
})

View File

@ -1,25 +0,0 @@
'use strict'
const post = require('./models/post')
const meta = require('./models/meta')
const replyAllView = require('./views/reply-all')
const ssbRef = require('ssb-ref')
module.exports = async function replyPage (parentId) {
const parentMessage = await post.get(parentId)
const myFeedId = await meta.myFeedId()
const hasRoot = typeof parentMessage.value.content.root === 'string' && ssbRef.isMsg(parentMessage.value.content.root)
const rootMessage = hasRoot
? await post.get(parentMessage.value.content.root)
: parentMessage
const messages = hasRoot
? await post.fromRoot(parentMessage.value.content.root)
: await post.fromRoot(parentId)
messages.push(rootMessage)
return replyAllView({ messages, myFeedId, parentMessage })
}

View File

@ -10,9 +10,7 @@ module.exports = async function replyPage (parentId) {
const myFeedId = await meta.myFeedId()
debug('%O', rootMessage)
const messages = await post.fromRoot(rootMessage.key)
messages.push(rootMessage)
const messages = [rootMessage]
return replyView({ messages, myFeedId })
}

View File

@ -1,12 +1,15 @@
'use strict'
const {
a,
button,
form,
textarea
textarea,
p,
strong
} = require('hyperaxe')
const debug = require('debug')('oasis:views:reply-all')
const debug = require('debug')('oasis:views:comment')
const template = require('./components/template')
const post = require('./components/post')
@ -28,11 +31,19 @@ module.exports = async ({ messages, myFeedId, parentMessage }) => {
})
)
const action = `/reply-all/${encodeURIComponent(messages[0].key)}`
const action = `/comment/${encodeURIComponent(messages[0].key)}`
const method = 'post'
return template(
messageElements,
p('Write a ',
strong('public comment'),
' on this thread with ',
a({ href: 'https://commonmark.org/help/' }, 'Markdown'),
'. Messages cannot be edited or deleted. To respond to an individual message, select ',
strong('reply'),
' instead.'
),
form({ action, method },
textarea({
autofocus: true,
@ -41,6 +52,6 @@ module.exports = async ({ messages, myFeedId, parentMessage }) => {
}, markdownMention),
button({
type: 'submit'
}, 'reply all'))
}, 'comment'))
)
}

View File

@ -34,7 +34,7 @@ module.exports = ({ msg }) => {
avatar: msg.value.meta.author.avatar.url,
json: `/json/${encoded.key}`,
reply: `/reply/${encoded.key}`,
replyAll: `/reply-all/${encoded.key}`
comment: `/comment/${encoded.key}`
}
const isPrivate = Boolean(msg.value.meta.private)
@ -81,8 +81,8 @@ module.exports = ({ msg }) => {
const postOptions = {
post: null,
replyAll: [
'replied to ',
comment: [
'commented on ',
a({ href: url.parent }, ' thread')
],
reply: [
@ -151,7 +151,7 @@ module.exports = ({ msg }) => {
},
`${likeCount}`)),
(isPrivate || isRoot) ? null : a({ href: url.reply }, 'reply'),
isPrivate ? null : a({ href: url.replyAll }, 'reply all'),
isPrivate ? null : a({ href: url.comment }, 'comment'),
a({ href: url.json }, 'json')
))

View File

@ -1,6 +1,9 @@
'use strict'
const {
p,
a,
strong,
button,
form,
textarea
@ -11,7 +14,7 @@ const template = require('./components/template')
const post = require('./components/post')
module.exports = async ({ messages, myFeedId }) => {
const likeForm = `/reply/${encodeURIComponent(messages[0].key)}`
const replyForm = `/reply/${encodeURIComponent(messages[messages.length - 1].key)}`
let markdownMention
@ -32,7 +35,15 @@ module.exports = async ({ messages, myFeedId }) => {
return template(
messageElements,
form({ action: likeForm, method: 'post' },
p('Write a ',
strong('public reply'),
' to this message with ',
a({ href: 'https://commonmark.org/help/' }, 'Markdown'),
'. Messages cannot be edited or deleted. To respond to an entire thread, select ',
strong('comment'),
' instead.'
),
form({ action: replyForm, method: 'post' },
textarea({
autofocus: true,
required: true,