Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(files_sharing): Add share expiration indicator
Shares that would expire now shows a clock icon with a popover.

Signed-off-by: nfebe <[email protected]>
  • Loading branch information
nfebe committed Mar 27, 2025
commit e9ce055076ee98392361ec0369c243b593f29885
78 changes: 78 additions & 0 deletions apps/files_sharing/src/components/ShareExpiryTime.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!--
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div class="share-expiry-time">
<NcPopover popup-role="dialog">
<template #trigger>
<NcButton v-if="expiryTime"
class="hint-icon"
type="tertiary"
:aria-label="formattedExpiry">
<template #icon>
<ClockIcon :size="20" />
</template>
</NcButton>
</template>
<p v-if="expiryTime" class="hint-body">
{{ formattedExpiry }}
</p>
</NcPopover>
</div>
</template>

<script>
import NcButton from '@nextcloud/vue/components/NcButton'
import NcPopover from '@nextcloud/vue/components/NcPopover'
import ClockIcon from 'vue-material-design-icons/Clock.vue'

export default {
name: 'ShareExpiryTime',

components: {
NcButton,
NcPopover,
ClockIcon,
},

props: {
share: {
type: Object,
required: true,
},
},

computed: {
expiryTime() {
return this.share?.expireDate || null
},

formattedExpiry() {
return this.expiryTime
? this.t('files_sharing', 'Share expires on {datetime}', { datetime: this.expiryTime })
: ''
},
},
}
</script>

<style scoped lang="scss">
.share-expiry-time {
display: inline-flex;
align-items: center;
justify-content: center;

.hint-icon {
padding: 0;
margin: 0;
width: 24px;
height: 24px;
}
}

.hint-body {
padding: var(--border-radius-element);
max-width: 300px;
}
</style>
3 changes: 3 additions & 0 deletions apps/files_sharing/src/components/SharingEntry.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
: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
Expand All @@ -49,6 +50,7 @@ import NcSelect from '@nextcloud/vue/components/NcSelect'
import NcAvatar from '@nextcloud/vue/components/NcAvatar'
import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue'

import ShareExpiryTime from './ShareExpiryTime.vue'
import SharingEntryQuickShareSelect from './SharingEntryQuickShareSelect.vue'

import SharesMixin from '../mixins/SharesMixin.js'
Expand All @@ -62,6 +64,7 @@ export default {
NcAvatar,
DotsHorizontalIcon,
NcSelect,
ShareExpiryTime,
SharingEntryQuickShareSelect,
},

Expand Down
42 changes: 28 additions & 14 deletions apps/files_sharing/src/components/SharingEntryLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,26 @@
@open-sharing-details="openShareDetailsForCustomSettings(share)" />
</div>

<!-- clipboard -->
<NcActions v-if="share && (!isEmailShareType || isFileRequest) && share.token" ref="copyButton" class="sharing-entry__copy">
<NcActionButton :aria-label="copyLinkTooltip"
:title="copyLinkTooltip"
:href="shareLink"
@click.prevent="copyLink">
<template #icon>
<CheckIcon v-if="copied && copySuccess"
:size="20"
class="icon-checkmark-color" />
<ClipboardIcon v-else :size="20" />
</template>
</NcActionButton>
</NcActions>
<div class="sharing-entry__actions">
<ShareExpiryTime v-if="share && share.expireDate" :share="share" />

<!-- clipboard -->
<div>
<NcActions v-if="share && (!isEmailShareType || isFileRequest) && share.token" ref="copyButton" class="sharing-entry__copy">
<NcActionButton :aria-label="copyLinkTooltip"
:title="copyLinkTooltip"
:href="shareLink"
@click.prevent="copyLink">
<template #icon>
<CheckIcon v-if="copied && copySuccess"
:size="20"
class="icon-checkmark-color" />
<ClipboardIcon v-else :size="20" />
</template>
</NcActionButton>
</NcActions>
</div>
</div>
</div>

<!-- pending actions -->
Expand Down Expand Up @@ -245,6 +251,7 @@ import CloseIcon from 'vue-material-design-icons/Close.vue'
import PlusIcon from 'vue-material-design-icons/Plus.vue'

import SharingEntryQuickShareSelect from './SharingEntryQuickShareSelect.vue'
import ShareExpiryTime from './ShareExpiryTime.vue'

import ExternalShareAction from './ExternalShareAction.vue'
import GeneratePassword from '../utils/GeneratePassword.ts'
Expand Down Expand Up @@ -278,6 +285,7 @@ export default {
CloseIcon,
PlusIcon,
SharingEntryQuickShareSelect,
ShareExpiryTime,
},

mixins: [SharesMixin, ShareDetails],
Expand Down Expand Up @@ -936,6 +944,12 @@ export default {
}
}

&__actions {
display: flex;
align-items: center;
margin-inline-start: auto;
}

&:not(.sharing-entry--share) &__actions {
.new-share-link {
border-top: 1px solid var(--color-border);
Expand Down