diff options
Diffstat (limited to 'apps/files_sharing/src/components/SharingEntry.vue')
-rw-r--r-- | apps/files_sharing/src/components/SharingEntry.vue | 436 |
1 files changed, 92 insertions, 344 deletions
diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue index 2d29aaf1dc6..342b40ce384 100644 --- a/apps/files_sharing/src/components/SharingEntry.vue +++ b/apps/files_sharing/src/components/SharingEntry.vue @@ -1,199 +1,101 @@ <!-- - - @copyright Copyright (c) 2019 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: 2019 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> <li class="sharing-entry"> - <Avatar class="sharing-entry__avatar" - :is-no-user="share.type !== SHARE_TYPES.SHARE_TYPE_USER" + <NcAvatar class="sharing-entry__avatar" + :is-no-user="share.type !== ShareType.User" :user="share.shareWith" :display-name="share.shareWithDisplayName" - :tooltip-message="share.type === SHARE_TYPES.SHARE_TYPE_USER ? share.shareWith : ''" :menu-position="'left'" :url="share.shareWithAvatar" /> - <component :is="share.shareWithLink ? 'a' : 'div'" - v-tooltip.auto="tooltip" - :href="share.shareWithLink" - class="sharing-entry__desc"> - <h5>{{ title }}<span v-if="!isUnique" class="sharing-entry__desc-unique"> ({{ share.shareWithDisplayNameUnique }})</span></h5> - <p v-if="hasStatus"> - <span>{{ share.status.icon || '' }}</span> - <span>{{ share.status.message || '' }}</span> - </p> - </component> - <Actions menu-align="right" - class="sharing-entry__actions" - @close="onMenuClose"> - <template v-if="share.canEdit"> - <!-- edit permission --> - <ActionCheckbox ref="canEdit" - :checked.sync="canEdit" - :value="permissionsEdit" - :disabled="saving || !canSetEdit"> - {{ t('files_sharing', 'Allow editing') }} - </ActionCheckbox> - <!-- create permission --> - <ActionCheckbox v-if="isFolder" - ref="canCreate" - :checked.sync="canCreate" - :value="permissionsCreate" - :disabled="saving || !canSetCreate"> - {{ t('files_sharing', 'Allow creating') }} - </ActionCheckbox> - - <!-- delete permission --> - <ActionCheckbox v-if="isFolder" - ref="canDelete" - :checked.sync="canDelete" - :value="permissionsDelete" - :disabled="saving || !canSetDelete"> - {{ t('files_sharing', 'Allow deleting') }} - </ActionCheckbox> - - <!-- reshare permission --> - <ActionCheckbox v-if="config.isResharingAllowed" - ref="canReshare" - :checked.sync="canReshare" - :value="permissionsShare" - :disabled="saving || !canSetReshare"> - {{ t('files_sharing', 'Allow resharing') }} - </ActionCheckbox> - - <!-- expiration date --> - <ActionCheckbox :checked.sync="hasExpirationDate" - :disabled="config.isDefaultInternalExpireDateEnforced || saving" - @uncheck="onExpirationDisable"> - {{ config.isDefaultInternalExpireDateEnforced - ? t('files_sharing', 'Expiration date enforced') - : t('files_sharing', 'Set expiration date') }} - </ActionCheckbox> - <ActionInput v-if="hasExpirationDate" - ref="expireDate" - v-tooltip.auto="{ - content: errors.expireDate, - show: errors.expireDate, - trigger: 'manual' - }" - :class="{ error: errors.expireDate}" - :disabled="saving" - :lang="lang" - :value="share.expireDate" - value-type="format" - icon="icon-calendar-dark" - type="date" - :disabled-date="disabledDate" - @update:value="onExpirationChange"> - {{ t('files_sharing', 'Enter a date') }} - </ActionInput> - - <!-- note --> - <template v-if="canHaveNote"> - <ActionCheckbox :checked.sync="hasNote" - :disabled="saving" - @uncheck="queueUpdate('note')"> - {{ t('files_sharing', 'Note to recipient') }} - </ActionCheckbox> - <ActionTextEditable v-if="hasNote" - ref="note" - v-tooltip.auto="{ - content: errors.note, - show: errors.note, - trigger: 'manual' - }" - :class="{ error: errors.note}" - :disabled="saving" - :value="share.newNote || share.note" - icon="icon-edit" - @update:value="onNoteChange" - @submit="onNoteSubmit" /> - </template> + <div class="sharing-entry__summary"> + <component :is="share.shareWithLink ? 'a' : 'div'" + :title="tooltip" + :aria-label="tooltip" + :href="share.shareWithLink" + class="sharing-entry__summary__desc"> + <span>{{ title }} + <span v-if="!isUnique" class="sharing-entry__summary__desc-unique"> + ({{ share.shareWithDisplayNameUnique }}) + </span> + <small v-if="hasStatus && share.status.message">({{ share.status.message }})</small> + </span> + </component> + <SharingEntryQuickShareSelect :share="share" + :file-info="fileInfo" + @open-sharing-details="openShareDetailsForCustomSettings(share)" /> + </div> + <ShareExpiryTime v-if="share && share.expireDate" :share="share" /> + <NcButton v-if="share.canEdit" + class="sharing-entry__action" + data-cy-files-sharing-share-actions + :aria-label="t('files_sharing', 'Open Sharing Details')" + type="tertiary" + @click="openSharingDetails(share)"> + <template #icon> + <DotsHorizontalIcon :size="20" /> </template> - - <ActionButton v-if="share.canDelete" - icon="icon-close" - :disabled="saving" - @click.prevent="onDelete"> - {{ t('files_sharing', 'Unshare') }} - </ActionButton> - </Actions> + </NcButton> </li> </template> <script> -import Avatar from '@nextcloud/vue/dist/Components/Avatar' -import Actions from '@nextcloud/vue/dist/Components/Actions' -import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' -import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox' -import ActionInput from '@nextcloud/vue/dist/Components/ActionInput' -import ActionTextEditable from '@nextcloud/vue/dist/Components/ActionTextEditable' -import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip' +import { ShareType } from '@nextcloud/sharing' + +import NcButton from '@nextcloud/vue/components/NcButton' +import NcSelect from '@nextcloud/vue/components/NcSelect' +import NcAvatar from '@nextcloud/vue/components/NcAvatar' +import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue' -import SharesMixin from '../mixins/SharesMixin' +import ShareExpiryTime from './ShareExpiryTime.vue' +import SharingEntryQuickShareSelect from './SharingEntryQuickShareSelect.vue' + +import SharesMixin from '../mixins/SharesMixin.js' +import ShareDetails from '../mixins/ShareDetails.js' export default { name: 'SharingEntry', components: { - Actions, - ActionButton, - ActionCheckbox, - ActionInput, - ActionTextEditable, - Avatar, - }, - - directives: { - Tooltip, + NcButton, + NcAvatar, + DotsHorizontalIcon, + NcSelect, + ShareExpiryTime, + SharingEntryQuickShareSelect, }, - mixins: [SharesMixin], - - data() { - return { - permissionsEdit: OC.PERMISSION_UPDATE, - permissionsCreate: OC.PERMISSION_CREATE, - permissionsDelete: OC.PERMISSION_DELETE, - permissionsRead: OC.PERMISSION_READ, - permissionsShare: OC.PERMISSION_SHARE, - } - }, + mixins: [SharesMixin, ShareDetails], computed: { title() { let title = this.share.shareWithDisplayName - if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_GROUP) { + + const showAsInternal = this.config.showFederatedSharesAsInternal + || (this.share.isTrustedServer && this.config.showFederatedSharesToTrustedServersAsInternal) + + if (this.share.type === ShareType.Group || (this.share.type === ShareType.RemoteGroup && showAsInternal)) { title += ` (${t('files_sharing', 'group')})` - } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_ROOM) { + } else if (this.share.type === ShareType.Room) { title += ` (${t('files_sharing', 'conversation')})` - } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_REMOTE) { + } else if (this.share.type === ShareType.Remote && !showAsInternal) { title += ` (${t('files_sharing', 'remote')})` - } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_REMOTE_GROUP) { + } else if (this.share.type === ShareType.RemoteGroup) { title += ` (${t('files_sharing', 'remote group')})` - } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_GUEST) { + } else if (this.share.type === ShareType.Guest) { title += ` (${t('files_sharing', 'guest')})` } + if (!this.isShareOwner && this.share.ownerDisplayName) { + title += ' ' + t('files_sharing', 'by {initiator}', { + initiator: this.share.ownerDisplayName, + }) + } return title }, - tooltip() { if (this.share.owner !== this.share.uidFileOwner) { const data = { @@ -202,10 +104,9 @@ export default { user: this.share.shareWithDisplayName, owner: this.share.ownerDisplayName, } - - if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_GROUP) { + if (this.share.type === ShareType.Group) { return t('files_sharing', 'Shared with the group {user} by {owner}', data) - } else if (this.share.type === this.SHARE_TYPES.SHARE_TYPE_ROOM) { + } else if (this.share.type === ShareType.Room) { return t('files_sharing', 'Shared with the conversation {user} by {owner}', data) } @@ -214,185 +115,19 @@ export default { return null }, - canHaveNote() { - return !this.isRemote - }, - - isRemote() { - return this.share.type === this.SHARE_TYPES.SHARE_TYPE_REMOTE - || this.share.type === this.SHARE_TYPES.SHARE_TYPE_REMOTE_GROUP - }, - - /** - * Can the sharer set whether the sharee can edit the file ? - * - * @return {boolean} - */ - canSetEdit() { - // If the owner revoked the permission after the resharer granted it - // the share still has the permission, and the resharer is still - // allowed to revoke it too (but not to grant it again). - return (this.fileInfo.sharePermissions & OC.PERMISSION_UPDATE) || this.canEdit - }, - - /** - * Can the sharer set whether the sharee can create the file ? - * - * @return {boolean} - */ - canSetCreate() { - // If the owner revoked the permission after the resharer granted it - // the share still has the permission, and the resharer is still - // allowed to revoke it too (but not to grant it again). - return (this.fileInfo.sharePermissions & OC.PERMISSION_CREATE) || this.canCreate - }, - - /** - * Can the sharer set whether the sharee can delete the file ? - * - * @return {boolean} - */ - canSetDelete() { - // If the owner revoked the permission after the resharer granted it - // the share still has the permission, and the resharer is still - // allowed to revoke it too (but not to grant it again). - return (this.fileInfo.sharePermissions & OC.PERMISSION_DELETE) || this.canDelete - }, - - /** - * Can the sharer set whether the sharee can reshare the file ? - * - * @return {boolean} - */ - canSetReshare() { - // If the owner revoked the permission after the resharer granted it - // the share still has the permission, and the resharer is still - // allowed to revoke it too (but not to grant it again). - return (this.fileInfo.sharePermissions & OC.PERMISSION_SHARE) || this.canReshare - }, - - /** - * Can the sharee edit the shared file ? - */ - canEdit: { - get() { - return this.share.hasUpdatePermission - }, - set(checked) { - this.updatePermissions({ isEditChecked: checked }) - }, - }, - - /** - * Can the sharee create the shared file ? - */ - canCreate: { - get() { - return this.share.hasCreatePermission - }, - set(checked) { - this.updatePermissions({ isCreateChecked: checked }) - }, - }, - - /** - * Can the sharee delete the shared file ? - */ - canDelete: { - get() { - return this.share.hasDeletePermission - }, - set(checked) { - this.updatePermissions({ isDeleteChecked: checked }) - }, - }, - - /** - * Can the sharee reshare the file ? - */ - canReshare: { - get() { - return this.share.hasSharePermission - }, - set(checked) { - this.updatePermissions({ isReshareChecked: checked }) - }, - }, - - /** - * Is this share readable - * Needed for some federated shares that might have been added from file drop links - */ - hasRead: { - get() { - return this.share.hasReadPermission - }, - }, - - /** - * Is the current share a folder ? - * - * @return {boolean} - */ - isFolder() { - return this.fileInfo.type === 'dir' - }, - - /** - * Does the current share have an expiration date - * - * @return {boolean} - */ - hasExpirationDate: { - get() { - return this.config.isDefaultInternalExpireDateEnforced || !!this.share.expireDate - }, - set(enabled) { - this.share.expireDate = enabled - ? this.config.defaultInternalExpirationDateString !== '' - ? this.config.defaultInternalExpirationDateString - : moment().format('YYYY-MM-DD') - : '' - }, - }, - - dateMaxEnforced() { - if (!this.isRemote) { - return this.config.isDefaultInternalExpireDateEnforced - && moment().add(1 + this.config.defaultInternalExpireDate, 'days') - } else { - return this.config.isDefaultRemoteExpireDateEnforced - && moment().add(1 + this.config.defaultRemoteExpireDate, 'days') - } - }, - /** * @return {boolean} */ hasStatus() { - if (this.share.type !== this.SHARE_TYPES.SHARE_TYPE_USER) { + if (this.share.type !== ShareType.User) { return false } return (typeof this.share.status === 'object' && !Array.isArray(this.share.status)) }, - }, methods: { - updatePermissions({ isEditChecked = this.canEdit, isCreateChecked = this.canCreate, isDeleteChecked = this.canDelete, isReshareChecked = this.canReshare } = {}) { - // calc permissions if checked - const permissions = 0 - | (this.hasRead ? this.permissionsRead : 0) - | (isCreateChecked ? this.permissionsCreate : 0) - | (isDeleteChecked ? this.permissionsDelete : 0) - | (isEditChecked ? this.permissionsEdit : 0) - | (isReshareChecked ? this.permissionsShare : 0) - - this.share.permissions = permissions - this.queueUpdate('permissions') - }, - /** * Save potential changed data on menu close */ @@ -408,21 +143,34 @@ export default { display: flex; align-items: center; height: 44px; - &__desc { + &__summary { + padding: 8px; + padding-inline-start: 10px; display: flex; flex-direction: column; - justify-content: space-between; - padding: 8px; - line-height: 1.2em; - p { - color: var(--color-text-maxcontrast); - } - &-unique { - color: var(--color-text-maxcontrast); + justify-content: center; + align-items: flex-start; + flex: 1 0; + min-width: 0; + + &__desc { + display: inline-block; + padding-bottom: 0; + line-height: 1.2em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + p, + small { + color: var(--color-text-maxcontrast); + } + + &-unique { + color: var(--color-text-maxcontrast); + } } } - &__actions { - margin-left: auto; - } + } </style> |