mirror of
https://github.com/nextcloud/server.git
synced 2026-03-02 21:41:12 -05:00
feat(comments): Use activity tab to mount comments sidebar section if available
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
9c3350b313
commit
db2fec1cec
10 changed files with 386 additions and 98 deletions
|
|
@ -28,6 +28,8 @@ namespace OCA\Comments\Listener;
|
|||
|
||||
use OCA\Comments\AppInfo\Application;
|
||||
use OCA\Files\Event\LoadSidebar;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\Comments\ICommentsManager;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
|
|
@ -36,6 +38,8 @@ use OCP\Util;
|
|||
class LoadSidebarScripts implements IEventListener {
|
||||
public function __construct(
|
||||
private ICommentsManager $commentsManager,
|
||||
private IInitialState $initialState,
|
||||
private IAppManager $appManager,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +50,8 @@ class LoadSidebarScripts implements IEventListener {
|
|||
|
||||
$this->commentsManager->load();
|
||||
|
||||
$this->initialState->provideInitialState('activityEnabled', $this->appManager->isEnabledForUser('activity'));
|
||||
|
||||
// TODO: make sure to only include the sidebar script when
|
||||
// we properly split it between files list and sidebar
|
||||
Util::addScript(Application::APP_ID, 'comments');
|
||||
|
|
|
|||
85
apps/comments/src/comments-activity-tab.ts
Normal file
85
apps/comments/src/comments-activity-tab.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
*
|
||||
* @author Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
*
|
||||
* @license AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import moment from '@nextcloud/moment'
|
||||
import Vue from 'vue'
|
||||
import logger from './logger.js'
|
||||
import { getComments } from './services/GetComments.js'
|
||||
|
||||
let ActivityTabPluginView
|
||||
let ActivityTabPluginInstance
|
||||
|
||||
/**
|
||||
* Register the comments plugins for the Activity sidebar
|
||||
*/
|
||||
export function registerCommentsPlugins() {
|
||||
window.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()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
window.OCA.Activity.registerSidebarEntries(async ({ fileInfo, limit, offset }) => {
|
||||
const { data: comments } = await getComments({ commentsType: 'files', ressourceId: fileInfo.id }, { limit, offset })
|
||||
logger.debug('Loaded comments', { fileInfo, comments })
|
||||
const { default: CommentView } = await import('./views/ActivityCommentEntry.vue')
|
||||
const CommentsViewObject = Vue.extend(CommentView)
|
||||
|
||||
return comments.map((comment) => ({
|
||||
timestamp: moment(comment.props.creationDateTime).toDate().getTime(),
|
||||
mount(element, { context, reload }) {
|
||||
this._CommentsViewInstance = new CommentsViewObject({
|
||||
parent: context,
|
||||
propsData: {
|
||||
comment,
|
||||
ressourceId: fileInfo.id,
|
||||
reloadCallback: reload,
|
||||
},
|
||||
})
|
||||
this._CommentsViewInstance.$mount(element)
|
||||
},
|
||||
unmount() {
|
||||
this._CommentsViewInstance.$destroy()
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
window.OCA.Activity.registerSidebarFilter((activity) => activity.type !== 'comments')
|
||||
logger.info('Comments plugin registered for Activity sidebar action')
|
||||
}
|
||||
|
|
@ -22,40 +22,53 @@
|
|||
|
||||
// eslint-disable-next-line n/no-missing-import, import/no-unresolved
|
||||
import MessageReplyText from '@mdi/svg/svg/message-reply-text.svg?raw'
|
||||
import { getRequestToken } from '@nextcloud/auth'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { registerCommentsPlugins } from './comments-activity-tab.ts'
|
||||
|
||||
// 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) {
|
||||
if (loadState('comments', 'activityEnabled', false) && OCA?.Activity?.registerSidebarAction !== undefined) {
|
||||
// Do not mount own tab but mount into activity
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
registerCommentsPlugins()
|
||||
})
|
||||
} 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 = 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()
|
||||
},
|
||||
})
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -235,6 +236,8 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
|
||||
/**
|
||||
* Update local Message on outer change
|
||||
*
|
||||
|
|
@ -279,7 +282,7 @@ $comment-padding: 10px;
|
|||
|
||||
.comment {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
gap: 8px;
|
||||
padding: 5px $comment-padding;
|
||||
|
||||
&__side {
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
@ -46,6 +47,7 @@ export default {
|
|||
deleted: false,
|
||||
editing: false,
|
||||
loading: false,
|
||||
commentsType: 'files',
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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'))
|
||||
|
|
@ -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
|
||||
|
|
|
|||
68
apps/comments/src/mixins/CommentView.ts
Normal file
68
apps/comments/src/mixins/CommentView.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
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))
|
||||
},
|
||||
|
||||
/**
|
||||
* Make sure we have all mentions as Array of objects
|
||||
*
|
||||
* @param mentions the mentions list
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
genMentionsData(mentions: any[]): Record<string, object> {
|
||||
Object.values(mentions)
|
||||
.flat()
|
||||
.forEach(mention => {
|
||||
this.userData[mention.mentionId] = {
|
||||
// TODO: support groups
|
||||
icon: 'icon-user',
|
||||
id: mention.mentionId,
|
||||
label: mention.mentionDisplayName,
|
||||
source: 'users',
|
||||
primary: getCurrentUser()?.uid === mention.mentionId,
|
||||
}
|
||||
})
|
||||
return this.userData
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { parseXML, type DAVResult, type FileStat } from 'webdav'
|
||||
import { parseXML, type DAVResult, type FileStat, type ResponseDataDetailed } from 'webdav'
|
||||
|
||||
// https://github.com/perry-mitchell/webdav-client/issues/339
|
||||
import { processResponsePayload } from '../../../../node_modules/webdav/dist/node/response.js'
|
||||
|
|
@ -37,11 +37,13 @@ export const DEFAULT_LIMIT = 20
|
|||
* @param {number} data.ressourceId the ressource ID
|
||||
* @param {object} [options] optional options for axios
|
||||
* @param {number} [options.offset] the pagination offset
|
||||
* @return {object[]} the comments list
|
||||
* @param {number} [options.limit] the pagination limit, defaults to 20
|
||||
* @param {Date} [options.datetime] optional date to query
|
||||
* @return {{data: object[]}} the comments list
|
||||
*/
|
||||
export const getComments = async function({ commentsType, ressourceId }, options: { offset: number }) {
|
||||
export const getComments = async function({ commentsType, ressourceId }, options: { offset: number, limit?: number, datetime?: Date }) {
|
||||
const ressourcePath = ['', commentsType, ressourceId].join('/')
|
||||
|
||||
const datetime = options.datetime ? `<oc:datetime>${options.datetime.toISOString()}</oc:datetime>` : ''
|
||||
const response = await client.customRequest(ressourcePath, Object.assign({
|
||||
method: 'REPORT',
|
||||
data: `<?xml version="1.0"?>
|
||||
|
|
@ -50,15 +52,16 @@ export const getComments = async function({ commentsType, ressourceId }, options
|
|||
xmlns:oc="http://owncloud.org/ns"
|
||||
xmlns:nc="http://nextcloud.org/ns"
|
||||
xmlns:ocs="http://open-collaboration-services.org/ns">
|
||||
<oc:limit>${DEFAULT_LIMIT}</oc:limit>
|
||||
<oc:limit>${options.limit ?? DEFAULT_LIMIT}</oc:limit>
|
||||
<oc:offset>${options.offset || 0}</oc:offset>
|
||||
${datetime}
|
||||
</oc:filter-comments>`,
|
||||
}, options))
|
||||
|
||||
const responseData = await response.text()
|
||||
const result = await parseXML(responseData)
|
||||
const stat = getDirectoryFiles(result, true)
|
||||
return processResponsePayload(response, stat, true)
|
||||
return processResponsePayload(response, stat, true) as ResponseDataDetailed<FileStat[]>
|
||||
}
|
||||
|
||||
// https://github.com/perry-mitchell/webdav-client/blob/8d9694613c978ce7404e26a401c39a41f125f87f/source/operations/directoryContents.ts
|
||||
|
|
|
|||
70
apps/comments/src/views/ActivityCommentAction.vue
Normal file
70
apps/comments/src/views/ActivityCommentAction.vue
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
-
|
||||
- @author Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
-
|
||||
- @license AGPL-3.0-or-later
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<Comment v-bind="editorData"
|
||||
:auto-complete="autoComplete"
|
||||
:user-data="userData"
|
||||
:editor="true"
|
||||
:ressource-id="ressourceId"
|
||||
class="comments-action"
|
||||
@new="onNewComment" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import Comment from '../components/Comment.vue'
|
||||
import CommentView from '../mixins/CommentView.js'
|
||||
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>
|
||||
|
||||
<style scoped>
|
||||
.comments-action {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
86
apps/comments/src/views/ActivityCommentEntry.vue
Normal file
86
apps/comments/src/views/ActivityCommentEntry.vue
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2023 Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
-
|
||||
- @author Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
-
|
||||
- @license AGPL-3.0-or-later
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<Comment ref="comment"
|
||||
tag="li"
|
||||
v-bind="comment.props"
|
||||
:auto-complete="autoComplete"
|
||||
:message="commentMessage"
|
||||
:ressource-id="ressourceId"
|
||||
:user-data="genMentionsData(comment.props.mentions)"
|
||||
class="comments-activity"
|
||||
@delete="reloadCallback()" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
|
||||
import Comment from '../components/Comment.vue'
|
||||
import CommentView from '../mixins/CommentView'
|
||||
|
||||
export default {
|
||||
name: 'ActivityCommentEntry',
|
||||
|
||||
components: {
|
||||
Comment,
|
||||
},
|
||||
|
||||
mixins: [CommentView],
|
||||
props: {
|
||||
comment: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
reloadCallback: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
commentMessage: '',
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
comment() {
|
||||
this.commentMessage = this.comment.props.message
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.commentMessage = this.comment.props.message
|
||||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.comments-activity {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -82,11 +82,8 @@
|
|||
</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'
|
||||
|
|
@ -101,6 +98,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)
|
||||
|
|
@ -109,7 +107,6 @@ export default {
|
|||
name: 'Comments',
|
||||
|
||||
components: {
|
||||
// Avatar,
|
||||
Comment,
|
||||
NcEmptyContent,
|
||||
NcButton,
|
||||
|
|
@ -118,6 +115,8 @@ export default {
|
|||
AlertCircleOutlineIcon,
|
||||
},
|
||||
|
||||
mixins: [CommentView],
|
||||
|
||||
data() {
|
||||
return {
|
||||
error: '',
|
||||
|
|
@ -130,12 +129,6 @@ export default {
|
|||
|
||||
cancelRequest: () => {},
|
||||
|
||||
editorData: {
|
||||
actorDisplayName: getCurrentUser().displayName,
|
||||
actorId: getCurrentUser().uid,
|
||||
key: 'editor',
|
||||
},
|
||||
|
||||
Comment,
|
||||
userData: {},
|
||||
}
|
||||
|
|
@ -151,6 +144,8 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
t,
|
||||
|
||||
async onVisibilityChange(isVisible) {
|
||||
if (isVisible) {
|
||||
try {
|
||||
|
|
@ -188,28 +183,6 @@ export default {
|
|||
this.getComments()
|
||||
},
|
||||
|
||||
/**
|
||||
* Make sure we have all mentions as Array of objects
|
||||
*
|
||||
* @param {any[]} mentions the mentions list
|
||||
* @return {Record<string, object>}
|
||||
*/
|
||||
genMentionsData(mentions) {
|
||||
Object.values(mentions)
|
||||
.flat()
|
||||
.forEach(mention => {
|
||||
this.userData[mention.mentionId] = {
|
||||
// TODO: support groups
|
||||
icon: 'icon-user',
|
||||
id: mention.mentionId,
|
||||
label: mention.mentionDisplayName,
|
||||
source: 'users',
|
||||
primary: getCurrentUser().uid === mention.mentionId,
|
||||
}
|
||||
})
|
||||
return this.userData
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the existing shares infos
|
||||
*/
|
||||
|
|
@ -255,27 +228,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
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue