Merge pull request #51630 from nextcloud/feat/47176/show-share-expiry

feat: Add share expiration indicator
This commit is contained in:
John Molakvoæ 2025-03-28 07:53:39 +01:00 committed by GitHub
commit d40cebb1c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 129 additions and 21 deletions

View file

@ -0,0 +1,91 @@
<!--
- 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="t('files_sharing', 'Share expiration: ') + new Date(expiryTime).toLocaleString()">
<template #icon>
<ClockIcon :size="20" />
</template>
</NcButton>
</template>
<h3 class="hint-heading">
{{ t('files_sharing', 'Share Expiration') }}
</h3>
<p v-if="expiryTime" class="hint-body">
<NcDateTime :timestamp="expiryTime"
:format="timeFormat"
:relative-time="false" /> (<NcDateTime :timestamp="expiryTime" />)
</p>
</NcPopover>
</div>
</template>
<script>
import NcButton from '@nextcloud/vue/components/NcButton'
import NcPopover from '@nextcloud/vue/components/NcPopover'
import NcDateTime from '@nextcloud/vue/components/NcDateTime'
import ClockIcon from 'vue-material-design-icons/Clock.vue'
export default {
name: 'ShareExpiryTime',
components: {
NcButton,
NcPopover,
NcDateTime,
ClockIcon,
},
props: {
share: {
type: Object,
required: true,
},
},
computed: {
expiryTime() {
return this.share?.expireDate ? new Date(this.share.expireDate).getTime() : null
},
timeFormat() {
return { dateStyle: 'full', timeStyle: 'short' }
},
},
}
</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-heading {
text-align: center;
font-size: 1rem;
margin-top: 8px;
padding-bottom: 8px;
margin-bottom: 0;
border-bottom: 1px solid var(--color-border);
}
.hint-body {
padding: var(--border-radius-element);
max-width: 300px;
}
</style>

View file

@ -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,
},

View file

@ -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);

2
dist/3738-3738.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
3738-3738.js.license

2
dist/4542-4542.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/4542-4542.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/4542-4542.js.map.license vendored Symbolic link
View file

@ -0,0 +1 @@
4542-4542.js.license

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long