diff options
author | fenn-cs <fenn25.fn@gmail.com> | 2023-07-19 02:11:27 +0100 |
---|---|---|
committer | Louis Chemineau <louis@chmn.me> | 2023-08-30 18:12:49 +0200 |
commit | 8b42fb033fdcd3775b4850de6faf6091c8dcc716 (patch) | |
tree | 7ca9ccb33d95090ae4a34e24ef650d0eede8732d /apps/files_sharing/src/components/SharingEntry.vue | |
parent | 191e20d7f48338ca336fd0091301653251fc0667 (diff) | |
download | nextcloud-server-8b42fb033fdcd3775b4850de6faf6091c8dcc716.tar.gz nextcloud-server-8b42fb033fdcd3775b4850de6faf6091c8dcc716.zip |
Improve sharing flow
This commit introduces the following changes:
- Does not create new share once user is selected for internal shares
- Adds a `SharingDetails` view for share configurations
- Adds a quick share select to enable fast changes in share permisions.
Resolves: https://github.com/nextcloud/server/issues/26691
Signed-off-by: fenn-cs <fenn25.fn@gmail.com>
Signed-off-by: Louis Chemineau <louis@chmn.me>
Diffstat (limited to 'apps/files_sharing/src/components/SharingEntry.vue')
-rw-r--r-- | apps/files_sharing/src/components/SharingEntry.vue | 407 |
1 files changed, 54 insertions, 353 deletions
diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue index 46b65c695ee..7399617a79c 100644 --- a/apps/files_sharing/src/components/SharingEntry.vue +++ b/apps/files_sharing/src/components/SharingEntry.vue @@ -29,147 +29,64 @@ :menu-position="'left'" :url="share.shareWithAvatar" /> - <component :is="share.shareWithLink ? 'a' : 'div'" - :title="tooltip" - :aria-label="tooltip" - :href="share.shareWithLink" - class="sharing-entry__desc"> - <span>{{ title }}<span v-if="!isUnique" class="sharing-entry__desc-unique"> ({{ share.shareWithDisplayNameUnique }})</span></span> - <p v-if="hasStatus"> - <span>{{ share.status.icon || '' }}</span> - <span>{{ share.status.message || '' }}</span> - </p> - </component> - <NcActions menu-align="right" - class="sharing-entry__actions" - @close="onMenuClose"> - <template v-if="share.canEdit"> - <!-- edit permission --> - <NcActionCheckbox ref="canEdit" - :checked.sync="canEdit" - :value="permissionsEdit" - :disabled="saving || !canSetEdit"> - {{ t('files_sharing', 'Allow editing') }} - </NcActionCheckbox> - - <!-- create permission --> - <NcActionCheckbox v-if="isFolder" - ref="canCreate" - :checked.sync="canCreate" - :value="permissionsCreate" - :disabled="saving || !canSetCreate"> - {{ t('files_sharing', 'Allow creating') }} - </NcActionCheckbox> - - <!-- delete permission --> - <NcActionCheckbox v-if="isFolder" - ref="canDelete" - :checked.sync="canDelete" - :value="permissionsDelete" - :disabled="saving || !canSetDelete"> - {{ t('files_sharing', 'Allow deleting') }} - </NcActionCheckbox> - - <!-- reshare permission --> - <NcActionCheckbox v-if="config.isResharingAllowed" - ref="canReshare" - :checked.sync="canReshare" - :value="permissionsShare" - :disabled="saving || !canSetReshare"> - {{ t('files_sharing', 'Allow resharing') }} - </NcActionCheckbox> - - <NcActionCheckbox v-if="isSetDownloadButtonVisible" - ref="canDownload" - :checked.sync="canDownload" - :disabled="saving || !canSetDownload"> - {{ allowDownloadText }} - </NcActionCheckbox> - - <!-- expiration date --> - <NcActionCheckbox :checked.sync="hasExpirationDate" - :disabled="config.isDefaultInternalExpireDateEnforced || saving" - @uncheck="onExpirationDisable"> - {{ config.isDefaultInternalExpireDateEnforced - ? t('files_sharing', 'Expiration date enforced') - : t('files_sharing', 'Set expiration date') }} - </NcActionCheckbox> - <NcActionInput v-if="hasExpirationDate" - ref="expireDate" - :is-native-picker="true" - :hide-label="true" - :class="{ error: errors.expireDate}" - :disabled="saving" - :value="new Date(share.expireDate)" - type="date" - :min="dateTomorrow" - :max="dateMaxEnforced" - @input="onExpirationChange"> - {{ t('files_sharing', 'Enter a date') }} - </NcActionInput> - - <!-- note --> - <template v-if="canHaveNote"> - <NcActionCheckbox :checked.sync="hasNote" - :disabled="saving" - @uncheck="queueUpdate('note')"> - {{ t('files_sharing', 'Note to recipient') }} - </NcActionCheckbox> - <NcActionTextEditable v-if="hasNote" - ref="note" - :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" @click.prevent="toggleQuickShareSelect"> + <component :is="share.shareWithLink ? 'a' : 'div'" + :title="tooltip" + :aria-label="tooltip" + :href="share.shareWithLink" + class="sharing-entry__desc"> + <span>{{ title }}<span v-if="!isUnique" class="sharing-entry__desc-unique"> ({{ + share.shareWithDisplayNameUnique }})</span></span> + <p v-if="hasStatus"> + <span>{{ share.status.icon || '' }}</span> + <span>{{ share.status.message || '' }}</span> + </p> + </component> + <QuickShareSelect :share="share" + :file-info="fileInfo" + :toggle="showDropdown" + @open-sharing-details="openShareDetailsForCustomSettings(share)" /> + </div> + <NcButton class="sharing-entry__action" + :aria-label="t('files_sharing', 'Open Sharing Details')" + type="tertiary-no-background" + @click="openSharingDetails(share)"> + <template #icon> + <DotsHorizontalIcon :size="20" /> </template> - - <NcActionButton v-if="share.canDelete" - icon="icon-close" - :disabled="saving" - @click.prevent="onDelete"> - {{ t('files_sharing', 'Unshare') }} - </NcActionButton> - </NcActions> + </NcButton> </li> </template> <script> +import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' +import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js' import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js' -import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' -import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' -import NcActionCheckbox from '@nextcloud/vue/dist/Components/NcActionCheckbox.js' -import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js' -import NcActionTextEditable from '@nextcloud/vue/dist/Components/NcActionTextEditable.js' +import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue' + +import QuickShareSelect from './SharingEntryQuickShareSelect.vue' import SharesMixin from '../mixins/SharesMixin.js' +import ShareDetails from '../mixins/ShareDetails.js' export default { name: 'SharingEntry', components: { - NcActions, - NcActionButton, - NcActionCheckbox, - NcActionInput, - NcActionTextEditable, + NcButton, NcAvatar, + DotsHorizontalIcon, + NcSelect, + QuickShareSelect, }, - mixins: [SharesMixin], + mixins: [SharesMixin, ShareDetails], data() { return { - permissionsEdit: OC.PERMISSION_UPDATE, - permissionsCreate: OC.PERMISSION_CREATE, - permissionsDelete: OC.PERMISSION_DELETE, - permissionsRead: OC.PERMISSION_READ, - permissionsShare: OC.PERMISSION_SHARE, + showDropdown: false, } }, - computed: { title() { let title = this.share.shareWithDisplayName @@ -186,7 +103,6 @@ export default { } return title }, - tooltip() { if (this.share.owner !== this.share.uidFileOwner) { const data = { @@ -206,182 +122,6 @@ 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 sharer set whether the sharee can download the file ? - * - * @return {boolean} - */ - canSetDownload() { - // 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.canDownload() || this.canDownload) - }, - - /** - * 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 }) - }, - }, - - /** - * Can the sharee download files or only view them ? - */ - canDownload: { - get() { - return this.share.hasDownloadPermission - }, - set(checked) { - this.updatePermissions({ isDownloadChecked: 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) { - const defaultExpirationDate = this.config.defaultInternalExpirationDate - || new Date(new Date().setDate(new Date().getDate() + 1)) - this.share.expireDate = enabled - ? this.formatDateToString(defaultExpirationDate) - : '' - console.debug('Expiration date status', enabled, this.share.expireDate) - }, - }, - - dateMaxEnforced() { - if (!this.isRemote && this.config.isDefaultInternalExpireDateEnforced) { - return new Date(new Date().setDate(new Date().getDate() + 1 + this.config.defaultInternalExpireDate)) - } else if (this.config.isDefaultRemoteExpireDateEnforced) { - return new Date(new Date().setDate(new Date().getDate() + 1 + this.config.defaultRemoteExpireDate)) - } - return null - }, - /** * @return {boolean} */ @@ -392,70 +132,18 @@ export default { return (typeof this.share.status === 'object' && !Array.isArray(this.share.status)) }, - - /** - * @return {string} - */ - allowDownloadText() { - return t('files_sharing', 'Allow download') - }, - - /** - * @return {boolean} - */ - isSetDownloadButtonVisible() { - // TODO: Implement download permission for circle shares instead of hiding the option. - // https://github.com/nextcloud/server/issues/39161 - if (this.share && this.share.type === this.SHARE_TYPES.SHARE_TYPE_CIRCLE) { - return false - } - - const allowedMimetypes = [ - // Office documents - 'application/msword', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'application/vnd.ms-powerpoint', - 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'application/vnd.ms-excel', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'application/vnd.oasis.opendocument.text', - 'application/vnd.oasis.opendocument.spreadsheet', - 'application/vnd.oasis.opendocument.presentation', - ] - - return this.isFolder || allowedMimetypes.includes(this.fileInfo.mimetype) - }, }, methods: { - updatePermissions({ - isEditChecked = this.canEdit, - isCreateChecked = this.canCreate, - isDeleteChecked = this.canDelete, - isReshareChecked = this.canReshare, - isDownloadChecked = this.canDownload, - } = {}) { - // 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 - if (this.share.hasDownloadPermission !== isDownloadChecked) { - this.share.hasDownloadPermission = isDownloadChecked - } - this.queueUpdate('permissions', 'attributes') - }, - /** * Save potential changed data on menu close */ onMenuClose() { this.onNoteSubmit() }, + toggleQuickShareSelect() { + this.showDropdown = !this.showDropdown + }, }, } </script> @@ -465,21 +153,34 @@ export default { display: flex; align-items: center; height: 44px; + &__desc { display: flex; flex-direction: column; justify-content: space-between; - padding: 8px; + padding-bottom: 0; line-height: 1.2em; + p { color: var(--color-text-maxcontrast); } + &-unique { color: var(--color-text-maxcontrast); } } + &__actions { margin-left: auto; } + + &__summary { + padding: 8px; + display: flex; + flex-direction: column; + justify-content: center; + width: 100%; + } + } </style> |