summaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/src/components/SharingEntry.vue
diff options
context:
space:
mode:
authorfenn-cs <fenn25.fn@gmail.com>2023-07-19 02:11:27 +0100
committerLouis Chemineau <louis@chmn.me>2023-08-30 18:12:49 +0200
commit8b42fb033fdcd3775b4850de6faf6091c8dcc716 (patch)
tree7ca9ccb33d95090ae4a34e24ef650d0eede8732d /apps/files_sharing/src/components/SharingEntry.vue
parent191e20d7f48338ca336fd0091301653251fc0667 (diff)
downloadnextcloud-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.vue407
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>