aboutsummaryrefslogtreecommitdiffstats
path: root/apps/comments/src/views/Comments.vue
diff options
context:
space:
mode:
Diffstat (limited to 'apps/comments/src/views/Comments.vue')
-rw-r--r--apps/comments/src/views/Comments.vue231
1 files changed, 110 insertions, 121 deletions
diff --git a/apps/comments/src/views/Comments.vue b/apps/comments/src/views/Comments.vue
index c101c2c5c39..657af888a12 100644
--- a/apps/comments/src/views/Comments.vue
+++ b/apps/comments/src/views/Comments.vue
@@ -1,51 +1,44 @@
<!--
- - @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
- -
- - @author John Molakvoæ <skjnldsv@protonmail.com>
- -
- - @license GNU AGPL version 3 or any later version
- -
- - 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/>.
- -
- -->
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
<template>
- <div class="comments" :class="{ 'icon-loading': isFirstLoading }">
+ <div v-element-visibility="onVisibilityChange"
+ class="comments"
+ :class="{ 'icon-loading': isFirstLoading }">
<!-- Editor -->
<Comment v-bind="editorData"
:auto-complete="autoComplete"
+ :resource-type="resourceType"
:editor="true"
- :ressource-id="ressourceId"
+ :user-data="userData"
+ :resource-id="currentResourceId"
class="comments__writer"
@new="onNewComment" />
<template v-if="!isFirstLoading">
- <EmptyContent v-if="!hasComments && done" icon="icon-comment">
- {{ t('comments', 'No comments yet, start the conversation!') }}
- </EmptyContent>
-
- <!-- Comments -->
- <Comment v-for="comment in comments"
- v-else
- :key="comment.props.id"
- v-bind="comment.props"
- :auto-complete="autoComplete"
- :message.sync="comment.props.message"
- :ressource-id="ressourceId"
- :user-data="genMentionsData(comment.props.mentions)"
- class="comments__list"
- @delete="onDelete" />
+ <NcEmptyContent v-if="!hasComments && done"
+ class="comments__empty"
+ :name="t('comments', 'No comments yet, start the conversation!')">
+ <template #icon>
+ <IconMessageReplyTextOutline />
+ </template>
+ </NcEmptyContent>
+ <ul v-else>
+ <!-- Comments -->
+ <Comment v-for="comment in comments"
+ :key="comment.props.id"
+ tag="li"
+ v-bind="comment.props"
+ :auto-complete="autoComplete"
+ :resource-type="resourceType"
+ :message.sync="comment.props.message"
+ :resource-id="currentResourceId"
+ :user-data="genMentionsData(comment.props.mentions)"
+ class="comments__list"
+ @delete="onDelete" />
+ </ul>
<!-- Loading more message -->
<div v-if="loading && !isFirstLoading" class="comments__info icon-loading" />
@@ -55,62 +48,72 @@
</div>
<!-- Error message -->
- <EmptyContent v-else-if="error" class="comments__error" icon="icon-error">
- {{ error }}
- <template #desc>
- <button icon="icon-history" @click="getComments">
- {{ t('comments', 'Retry') }}
- </button>
- </template>
- </EmptyContent>
+ <template v-else-if="error">
+ <NcEmptyContent class="comments__error" :name="error">
+ <template #icon>
+ <IconAlertCircleOutline />
+ </template>
+ </NcEmptyContent>
+ <NcButton class="comments__retry" @click="getComments">
+ <template #icon>
+ <IconRefresh />
+ </template>
+ {{ t('comments', 'Retry') }}
+ </NcButton>
+ </template>
</template>
</div>
</template>
<script>
-import { generateOcsUrl } from '@nextcloud/router'
-import { getCurrentUser } from '@nextcloud/auth'
-import { loadState } from '@nextcloud/initial-state'
-import axios from '@nextcloud/axios'
-import VTooltip from 'v-tooltip'
-import Vue from 'vue'
-
-import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
-
-import Comment from '../components/Comment'
-import getComments, { DEFAULT_LIMIT } from '../services/GetComments'
-import cancelableRequest from '../utils/cancelableRequest'
-
-Vue.use(VTooltip)
+import { showError } from '@nextcloud/dialogs'
+import { translate as t } from '@nextcloud/l10n'
+import { vElementVisibility as elementVisibility } from '@vueuse/components'
+
+import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
+import NcButton from '@nextcloud/vue/components/NcButton'
+import IconRefresh from 'vue-material-design-icons/Refresh.vue'
+import IconMessageReplyTextOutline from 'vue-material-design-icons/MessageReplyTextOutline.vue'
+import IconAlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
+
+import Comment from '../components/Comment.vue'
+import CommentView from '../mixins/CommentView'
+import cancelableRequest from '../utils/cancelableRequest.js'
+import { getComments, DEFAULT_LIMIT } from '../services/GetComments.ts'
+import { markCommentsAsRead } from '../services/ReadComments.ts'
export default {
name: 'Comments',
components: {
- // Avatar,
Comment,
- EmptyContent,
+ NcEmptyContent,
+ NcButton,
+ IconRefresh,
+ IconMessageReplyTextOutline,
+ IconAlertCircleOutline,
+ },
+
+ directives: {
+ elementVisibility,
},
+ mixins: [CommentView],
+
data() {
return {
error: '',
loading: false,
done: false,
- ressourceId: null,
+ currentResourceId: this.resourceId,
offset: 0,
comments: [],
cancelRequest: () => {},
- editorData: {
- actorDisplayName: getCurrentUser().displayName,
- actorId: getCurrentUser().uid,
- key: 'editor',
- },
-
Comment,
+ userData: {},
}
},
@@ -123,14 +126,32 @@ export default {
},
},
+ watch: {
+ resourceId() {
+ this.currentResourceId = this.resourceId
+ },
+ },
+
methods: {
+ t,
+
+ async onVisibilityChange(isVisible) {
+ if (isVisible) {
+ try {
+ await markCommentsAsRead(this.resourceType, this.currentResourceId, new Date())
+ } catch (e) {
+ showError(e.message || t('comments', 'Failed to mark comments as read'))
+ }
+ }
+ },
+
/**
- * Update current ressourceId and fetch new data
+ * Update current resourceId and fetch new data
*
- * @param {number} ressourceId the current ressourceId (fileId...)
+ * @param {number} resourceId the current resourceId (fileId...)
*/
- async update(ressourceId) {
- this.ressourceId = ressourceId
+ async update(resourceId) {
+ this.currentResourceId = resourceId
this.resetState()
this.getComments()
},
@@ -152,27 +173,6 @@ export default {
},
/**
- * Make sure we have all mentions as Array of objects
- *
- * @param {Array} mentions the mentions list
- * @return {object[]}
- */
- genMentionsData(mentions) {
- const list = Object.values(mentions).flat()
- return list.reduce((mentions, mention) => {
- mentions[mention.mentionId] = {
- // TODO: support groups
- icon: 'icon-user',
- id: mention.mentionId,
- label: mention.mentionDisplayName,
- source: 'users',
- primary: getCurrentUser().uid === mention.mentionId,
- }
- return mentions
- }, {})
- },
-
- /**
* Get the existing shares infos
*/
async getComments() {
@@ -184,14 +184,14 @@ export default {
this.error = ''
// Init cancellable request
- const { request, cancel } = cancelableRequest(getComments)
- this.cancelRequest = cancel
+ const { request, abort } = cancelableRequest(getComments)
+ this.cancelRequest = abort
// Fetch comments
- const comments = await request({
- commentsType: this.commentsType,
- ressourceId: this.ressourceId,
- }, { offset: this.offset })
+ const { data: comments } = await request({
+ resourceType: this.resourceType,
+ resourceId: this.currentResourceId,
+ }, { offset: this.offset }) || { data: [] }
this.logger.debug(`Processed ${comments.length} comments`, { comments })
@@ -218,25 +218,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'),
- },
- })
- return callback(results.data.ocs.data)
- },
-
- /**
* Add newly created comment to the list
*
* @param {object} comment the new comment
@@ -275,9 +256,17 @@ export default {
<style lang="scss" scoped>
.comments {
- // Do not add emptycontent top margin
- &__error{
- margin-top: 0;
+ min-height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ &__empty,
+ &__error {
+ flex: 1 0;
+ }
+
+ &__retry {
+ margin: 0 auto;
}
&__info {