Skip to content

Commit b92f1cc

Browse files
Expose public token editor in sharing sidebar
Signed-off-by: Alexander Rebello <me@alexander-rebello.de>
1 parent be327ac commit b92f1cc

1 file changed

Lines changed: 133 additions & 5 deletions

File tree

src/components/SidebarTabs/SharingSidebarTab.vue

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,23 @@
5353
<IconLinkBoxVariantOutline v-if="isEmbeddable" :size="20" />
5454
<IconLinkVariant v-else :size="20" />
5555
</div>
56-
<span class="share-div__desc">{{
57-
isEmbeddable
58-
? t('forms', 'Embeddable link')
59-
: t('forms', 'Share link')
60-
}}</span>
56+
<div class="share-div__desc share-div__desc--tokenized">
57+
<span>{{
58+
isEmbeddable
59+
? t('forms', 'Embeddable link')
60+
: t('forms', 'Share link')
61+
}}</span>
62+
<NcTextField
63+
v-if="appConfig.allowCustomPublicShareTokens"
64+
:modelValue="getShareTokenInput(share)"
65+
:disabled="
66+
locked
67+
|| !isCurrentUserOwner
68+
|| isShareTokenSaving(share)
69+
"
70+
:label="t('forms', 'Link token')"
71+
@update:modelValue="setShareTokenInput(share, $event)" />
72+
</div>
6173
<NcActions :inline="1">
6274
<NcActionLink
6375
:href="getPublicShareLink(share)"
@@ -73,6 +85,20 @@
7385
</template>
7486
{{ t('forms', 'Show QR code') }}
7587
</NcActionButton>
88+
<NcActionButton
89+
v-if="appConfig.allowCustomPublicShareTokens"
90+
:disabled="
91+
locked
92+
|| !isCurrentUserOwner
93+
|| isShareTokenSaving(share)
94+
|| !isShareTokenDirty(share)
95+
"
96+
@click="updateShareToken(share)">
97+
<template #icon>
98+
<IconCheck :size="20" />
99+
</template>
100+
{{ t('forms', 'Save token') }}
101+
</NcActionButton>
76102
<NcActionButton
77103
v-if="isEmbeddable"
78104
@click="copyEmbeddingCode(share)">
@@ -212,7 +238,9 @@ import NcActionLink from '@nextcloud/vue/components/NcActionLink'
212238
import NcActions from '@nextcloud/vue/components/NcActions'
213239
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
214240
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
241+
import NcTextField from '@nextcloud/vue/components/NcTextField'
215242
import IconAccountMultiple from 'vue-material-design-icons/AccountMultipleOutline.vue'
243+
import IconCheck from 'vue-material-design-icons/Check.vue'
216244
import IconCodeBrackets from 'vue-material-design-icons/CodeBrackets.vue'
217245
import IconLinkVariant from 'vue-material-design-icons/Link.vue'
218246
import IconLinkBoxVariantOutline from 'vue-material-design-icons/LinkBoxOutline.vue'
@@ -234,6 +262,7 @@ export default {
234262
components: {
235263
FormsIcon,
236264
IconAccountMultiple,
265+
IconCheck,
237266
IconCodeBrackets,
238267
IconCopyAll,
239268
IconDelete,
@@ -246,6 +275,7 @@ export default {
246275
NcActionLink,
247276
NcCheckboxRadioSwitch,
248277
NcNoteCard,
278+
NcTextField,
249279
QRDialog,
250280
SharingSearchDiv,
251281
SharingShareDiv,
@@ -276,10 +306,27 @@ export default {
276306
return {
277307
isLoading: false,
278308
appConfig: loadState(appName, 'appConfig'),
309+
shareTokens: {},
310+
savingShareTokens: {},
279311
qrDialogText: '',
280312
}
281313
},
282314
315+
watch: {
316+
publicLinkShares: {
317+
immediate: true,
318+
handler(shares) {
319+
const nextShareTokens = {}
320+
for (const share of shares) {
321+
nextShareTokens[share.id] =
322+
this.shareTokens[share.id] ?? share.shareWith
323+
}
324+
325+
this.shareTokens = nextShareTokens
326+
},
327+
},
328+
},
329+
283330
computed: {
284331
isCurrentUserOwner() {
285332
return getCurrentUser().uid === this.form.ownerId
@@ -480,6 +527,76 @@ export default {
480527
this.$emit('update:formProp', 'access', newAccess)
481528
},
482529
530+
getShareTokenInput(share) {
531+
return this.shareTokens[share.id] ?? share.shareWith
532+
},
533+
534+
setShareTokenInput(share, value) {
535+
this.shareTokens = {
536+
...this.shareTokens,
537+
[share.id]: value,
538+
}
539+
},
540+
541+
isShareTokenSaving(share) {
542+
return !!this.savingShareTokens[share.id]
543+
},
544+
545+
isShareTokenDirty(share) {
546+
return this.getShareTokenInput(share).trim() !== share.shareWith
547+
},
548+
549+
async updateShareToken(share) {
550+
const token = this.getShareTokenInput(share).trim()
551+
if (token === share.shareWith) {
552+
return
553+
}
554+
555+
this.isLoading = true
556+
this.savingShareTokens = {
557+
...this.savingShareTokens,
558+
[share.id]: true,
559+
}
560+
561+
try {
562+
const response = await axios.patch(
563+
generateOcsUrl(
564+
'apps/forms/api/v3/forms/{id}/shares/{shareId}/token',
565+
{
566+
id: this.form.id,
567+
shareId: share.id,
568+
},
569+
),
570+
{
571+
token,
572+
},
573+
)
574+
575+
this.$emit('updateShare', {
576+
...share,
577+
id: OcsResponse2Data(response),
578+
shareWith: token,
579+
})
580+
581+
this.setShareTokenInput(share, token)
582+
} catch (error) {
583+
logger.error('Error while updating share token', {
584+
error,
585+
share,
586+
token,
587+
})
588+
showError(
589+
t('forms', 'There was an error while updating the link token'),
590+
)
591+
} finally {
592+
this.savingShareTokens = {
593+
...this.savingShareTokens,
594+
[share.id]: false,
595+
}
596+
this.isLoading = false
597+
}
598+
},
599+
483600
openQrDialog(share) {
484601
this.qrDialogText = this.getPublicShareLink(share)
485602
},
@@ -534,6 +651,13 @@ export default {
534651
padding: 0px 8px;
535652
flex-grow: 1;
536653
654+
&--tokenized {
655+
display: flex;
656+
flex-direction: column;
657+
justify-content: center;
658+
padding-block: 8px;
659+
}
660+
537661
&--twoline {
538662
span {
539663
display: block;
@@ -545,5 +669,9 @@ export default {
545669
}
546670
}
547671
}
672+
673+
:deep(.share-div__desc--tokenized .input-field__main-wrapper) {
674+
min-inline-size: 220px;
675+
}
548676
}
549677
</style>

0 commit comments

Comments
 (0)