aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornfebe <fenn25.fn@gmail.com>2025-03-20 23:49:15 +0100
committernfebe <fenn25.fn@gmail.com>2025-03-27 19:56:05 +0100
commite9ce055076ee98392361ec0369c243b593f29885 (patch)
tree79c27a90fcdc3763224c60cf7a811b99c3fc0d66
parent1560fc835cc5e5346675b7230f958fda0067c68e (diff)
downloadnextcloud-server-e9ce055076ee98392361ec0369c243b593f29885.tar.gz
nextcloud-server-e9ce055076ee98392361ec0369c243b593f29885.zip
feat(files_sharing): Add share expiration indicator
Shares that would expire now shows a clock icon with a popover. Signed-off-by: nfebe <fenn25.fn@gmail.com>
-rw-r--r--apps/files_sharing/src/components/ShareExpiryTime.vue78
-rw-r--r--apps/files_sharing/src/components/SharingEntry.vue3
-rw-r--r--apps/files_sharing/src/components/SharingEntryLink.vue42
3 files changed, 109 insertions, 14 deletions
diff --git a/apps/files_sharing/src/components/ShareExpiryTime.vue b/apps/files_sharing/src/components/ShareExpiryTime.vue
new file mode 100644
index 00000000000..ab6ed2973c9
--- /dev/null
+++ b/apps/files_sharing/src/components/ShareExpiryTime.vue
@@ -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>
diff --git a/apps/files_sharing/src/components/SharingEntry.vue b/apps/files_sharing/src/components/SharingEntry.vue
index 3f8f03753d8..4ff5fae364b 100644
--- a/apps/files_sharing/src/components/SharingEntry.vue
+++ b/apps/files_sharing/src/components/SharingEntry.vue
@@ -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
@@ -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'
@@ -62,6 +64,7 @@ export default {
NcAvatar,
DotsHorizontalIcon,
NcSelect,
+ ShareExpiryTime,
SharingEntryQuickShareSelect,
},
diff --git a/apps/files_sharing/src/components/SharingEntryLink.vue b/apps/files_sharing/src/components/SharingEntryLink.vue
index e03370bb6e8..9427bd78967 100644
--- a/apps/files_sharing/src/components/SharingEntryLink.vue
+++ b/apps/files_sharing/src/components/SharingEntryLink.vue
@@ -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 -->
@@ -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'
@@ -278,6 +285,7 @@ export default {
CloseIcon,
PlusIcon,
SharingEntryQuickShareSelect,
+ ShareExpiryTime,
},
mixins: [SharesMixin, ShareDetails],
@@ -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);