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)"
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'
212238import NcActions from ' @nextcloud/vue/components/NcActions'
213239import NcCheckboxRadioSwitch from ' @nextcloud/vue/components/NcCheckboxRadioSwitch'
214240import NcNoteCard from ' @nextcloud/vue/components/NcNoteCard'
241+ import NcTextField from ' @nextcloud/vue/components/NcTextField'
215242import IconAccountMultiple from ' vue-material-design-icons/AccountMultipleOutline.vue'
243+ import IconCheck from ' vue-material-design-icons/Check.vue'
216244import IconCodeBrackets from ' vue-material-design-icons/CodeBrackets.vue'
217245import IconLinkVariant from ' vue-material-design-icons/Link.vue'
218246import 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