Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/comments/lib/Activity/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ protected function parseMessage(IEvent $event): void {

$commentId = $messageParameters['commentId'] ?? $messageParameters[0];

$event->setLink($this->url->linkTo('dav', join('/', ['comments', 'files', $event->getSubjectParameters()['fileId'] ?? $event->getObjectId(), $commentId])));

try {
$comment = $this->commentsManager->get((string) $commentId);
$message = $comment->getMessage();
Expand Down
124 changes: 91 additions & 33 deletions apps/comments/src/comments-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,98 @@

// eslint-disable-next-line n/no-missing-import, import/no-unresolved
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
// eslint-disable-next-line import/no-unresolved
import trashbinSVG from '@mdi/svg/svg/trash-can.svg?raw'
import { getCurrentUser, getRequestToken } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import Vue from 'vue'
import logger from './logger.js'
import deleteComment from './services/DeleteComment.js'

// Init Comments tab component
let TabInstance = null
const commentTab = new OCA.Files.Sidebar.Tab({
id: 'comments',
name: t('comments', 'Comments'),
iconSvg: MessageReplyText,
// @ts-expect-error __webpack_nonce__ is injected by webpack
__webpack_nonce__ = btoa(getRequestToken())

async mount(el, fileInfo, context) {
if (TabInstance) {
TabInstance.$destroy()
}
TabInstance = new OCA.Comments.View('files', {
// Better integration with vue parent component
parent: context,
if (loadState('comments', 'activityEnabled', true) && OCA?.Activity?.registerSidebarAction !== undefined) {
let ActivityTabPluginView
let ActivityTabPluginInstance

// Do mount own tab but mount into activity
window.addEventListener('DOMContentLoaded', function() {
OCA.Activity.registerSidebarAction({
mount: async (el, { context, fileInfo, reload }) => {
if (!ActivityTabPluginView) {
const { default: ActivityCommmentAction } = await import('./views/ActivityCommentAction.vue')
ActivityTabPluginView = Vue.extend(ActivityCommmentAction)
}
ActivityTabPluginInstance = new ActivityTabPluginView({
parent: context,
propsData: {
reloadCallback: reload,
ressourceId: fileInfo.id,
},
})
ActivityTabPluginInstance.$mount(el)
logger.info('Comments plugin mounted in Activity sidebar action', { fileInfo })
},
unmount: () => {
// destroy previous instance if available
if (ActivityTabPluginInstance) {
ActivityTabPluginInstance.$destroy()
}
},
})

OCA.Activity.registerAction('comments', ({ activity, reload }) => {
const actions = []
if (activity.user === getCurrentUser()?.uid) {
actions.push({
label: t('comments', 'Delete comment'),
icon: trashbinSVG,
handler: async (activity) => {
await deleteComment(...activity.link.split('/').slice(-3))
reload()
},
})
}
return actions
})
// Only mount after we have all the info we need
await TabInstance.update(fileInfo.id)
TabInstance.$mount(el)
},
update(fileInfo) {
TabInstance.update(fileInfo.id)
},
destroy() {
TabInstance.$destroy()
TabInstance = null
},
scrollBottomReached() {
TabInstance.onScrollBottomReached()
},
})
logger.info('Comments plugin registered for Activity sidebar action')
})
} else {
// Init Comments tab component
let TabInstance = null
const commentTab = new OCA.Files.Sidebar.Tab({
id: 'comments',
name: t('comments', 'Comments'),
iconSvg: MessageReplyText,

async mount(el, fileInfo, context) {
if (TabInstance) {
TabInstance.$destroy()
}
TabInstance = new OCA.Comments.View('files', {
// Better integration with vue parent component
parent: context,
})
// Only mount after we have all the info we need
await TabInstance.update(fileInfo.id)
TabInstance.$mount(el)
},
update(fileInfo) {
TabInstance.update(fileInfo.id)
},
destroy() {
TabInstance.$destroy()
TabInstance = null
},
scrollBottomReached() {
TabInstance.onScrollBottomReached()
},
})

window.addEventListener('DOMContentLoaded', function() {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(commentTab)
}
})
window.addEventListener('DOMContentLoaded', function() {
if (OCA.Files && OCA.Files.Sidebar) {
OCA.Files.Sidebar.registerTab(commentTab)
}
})
}
3 changes: 3 additions & 0 deletions apps/comments/src/components/Comment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@

<script>
import { getCurrentUser } from '@nextcloud/auth'
import { translate as t } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'

import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
Expand Down Expand Up @@ -235,6 +236,8 @@ export default {
},

methods: {
t,

/**
* Update local Message on outer change
*
Expand Down
10 changes: 6 additions & 4 deletions apps/comments/src/mixins/CommentMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
*
*/

import { showError, showUndo, TOAST_UNDO_TIMEOUT } from '@nextcloud/dialogs'
import NewComment from '../services/NewComment.js'
import DeleteComment from '../services/DeleteComment.js'
import EditComment from '../services/EditComment.js'
import { showError, showUndo, TOAST_UNDO_TIMEOUT } from '@nextcloud/dialogs'
import logger from '../logger.js'

export default {
props: {
Expand All @@ -46,6 +47,7 @@ export default {
deleted: false,
editing: false,
loading: false,
commentsType: 'files',
}
},

Expand All @@ -63,7 +65,7 @@ export default {
this.loading = true
try {
await EditComment(this.commentsType, this.ressourceId, this.id, message)
this.logger.debug('Comment edited', { commentsType: this.commentsType, ressourceId: this.ressourceId, id: this.id, message })
logger.debug('Comment edited', { commentsType: this.commentsType, ressourceId: this.ressourceId, id: this.id, message })
this.$emit('update:message', message)
this.editing = false
} catch (error) {
Expand All @@ -86,7 +88,7 @@ export default {
async onDelete() {
try {
await DeleteComment(this.commentsType, this.ressourceId, this.id)
this.logger.debug('Comment deleted', { commentsType: this.commentsType, ressourceId: this.ressourceId, id: this.id })
logger.debug('Comment deleted', { commentsType: this.commentsType, ressourceId: this.ressourceId, id: this.id })
this.$emit('delete', this.id)
} catch (error) {
showError(t('comments', 'An error occurred while trying to delete the comment'))
Expand All @@ -100,7 +102,7 @@ export default {
this.loading = true
try {
const newComment = await NewComment(this.commentsType, this.ressourceId, message)
this.logger.debug('New comment posted', { commentsType: this.commentsType, ressourceId: this.ressourceId, newComment })
logger.debug('New comment posted', { commentsType: this.commentsType, ressourceId: this.ressourceId, newComment })
this.$emit('new', newComment)

// Clear old content
Expand Down
46 changes: 46 additions & 0 deletions apps/comments/src/mixins/CommentView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import axios from '@nextcloud/axios'
import { getCurrentUser } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import { generateOcsUrl } from '@nextcloud/router'
import { defineComponent } from 'vue'

export default defineComponent({
props: {
ressourceId: {
type: Number,
required: true,
},
},
data() {
return {
editorData: {
actorDisplayName: getCurrentUser()!.displayName as string,
actorId: getCurrentUser()!.uid as string,
key: 'editor',
},
userData: {},
}
},
methods: {
/**
* Autocomplete @mentions
*
* @param {string} search the query
* @param {Function} callback the callback to process the results with
*/
async autoComplete(search, callback) {
const { data } = await axios.get(generateOcsUrl('core/autocomplete/get'), {
params: {
search,
itemType: 'files',
itemId: this.ressourceId,
sorter: 'commenters|share-recipients',
limit: loadState('comments', 'maxAutoCompleteResults'),
},
})
// Save user data so it can be used by the editor to replace mentions
data.ocs.data.forEach(user => { this.userData[user.id] = user })
return callback(Object.values(this.userData))
},
},
})
42 changes: 42 additions & 0 deletions apps/comments/src/views/ActivityCommentAction.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<template>
<Comment v-bind="editorData"
:auto-complete="autoComplete"
:user-data="userData"
:editor="true"
:ressource-id="ressourceId"
class="comments__writer"
@new="onNewComment" />
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import Comment from '../components/Comment.vue'
import CommentView from '../mixins/CommentView'
import logger from '../logger'
import { showError } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'

export default defineComponent({
components: {
Comment,
},
mixins: [CommentView],
props: {
reloadCallback: {
type: Function,
required: true,
},
},
methods: {
onNewComment() {
try {
// just force reload
this.reloadCallback()
} catch (e) {
showError(t('comments', 'Could not reload comments'))
logger.debug(e)
}
},
},
})
</script>
37 changes: 6 additions & 31 deletions apps/comments/src/views/Comments.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,9 @@
</template>

<script>
import { generateOcsUrl } from '@nextcloud/router'
import { getCurrentUser } from '@nextcloud/auth'
import { loadState } from '@nextcloud/initial-state'
import { showError } from '@nextcloud/dialogs'
import axios from '@nextcloud/axios'
import { translate as t } from '@nextcloud/l10n'
import VTooltip from 'v-tooltip'
import Vue from 'vue'
import VueObserveVisibility from 'vue-observe-visibility'
Expand All @@ -101,6 +99,7 @@ import Comment from '../components/Comment.vue'
import { getComments, DEFAULT_LIMIT } from '../services/GetComments.ts'
import cancelableRequest from '../utils/cancelableRequest.js'
import { markCommentsAsRead } from '../services/ReadComments.ts'
import CommentView from '../mixins/CommentView'

Vue.use(VTooltip)
Vue.use(VueObserveVisibility)
Expand All @@ -109,7 +108,6 @@ export default {
name: 'Comments',

components: {
// Avatar,
Comment,
NcEmptyContent,
NcButton,
Expand All @@ -118,6 +116,8 @@ export default {
AlertCircleOutlineIcon,
},

mixins: [CommentView],

data() {
return {
error: '',
Expand All @@ -130,12 +130,6 @@ export default {

cancelRequest: () => {},

editorData: {
actorDisplayName: getCurrentUser().displayName,
actorId: getCurrentUser().uid,
key: 'editor',
},

Comment,
userData: {},
}
Expand All @@ -151,6 +145,8 @@ export default {
},

methods: {
t,

async onVisibilityChange(isVisible) {
if (isVisible) {
try {
Expand Down Expand Up @@ -255,27 +251,6 @@ export default {
}
},

/**
* Autocomplete @mentions
*
* @param {string} search the query
* @param {Function} callback the callback to process the results with
*/
async autoComplete(search, callback) {
const results = await axios.get(generateOcsUrl('core/autocomplete/get'), {
params: {
search,
itemType: 'files',
itemId: this.ressourceId,
sorter: 'commenters|share-recipients',
limit: loadState('comments', 'maxAutoCompleteResults'),
},
})
// Save user data so it can be used by the editor to replace mentions
results.data.ocs.data.forEach(user => { this.userData[user.id] = user })
return callback(Object.values(this.userData))
},

/**
* Add newly created comment to the list
*
Expand Down
3 changes: 3 additions & 0 deletions dist/3591-3591.js

Large diffs are not rendered by default.

Loading