Skip to content

Commit 18c3220

Browse files
committed
add frontend handling of locked form
Signed-off-by: Christian Hartmann <[email protected]>
1 parent c1db32e commit 18c3220

14 files changed

+243
-28
lines changed

img/lock_open.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/AppNavigationForm.vue

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@
2525
<template v-if="hasSubtitle" #subname>
2626
{{ formSubtitle }}
2727
</template>
28-
<template v-if="!loading && !readOnly" #actions>
28+
<template
29+
v-if="!loading && (!readOnly || canEdit || canSeeResults)"
30+
#actions>
2931
<NcActionRouter
30-
v-if="!isArchived"
32+
v-if="!isArchived && canEdit"
3133
close-after-click
34+
:disabled="isFormLocked"
3235
exact
3336
:to="{ name: 'edit', params: { hash: form.hash } }"
3437
@click="mobileCloseNavigation">
@@ -38,7 +41,7 @@
3841
{{ t('forms', 'Edit form') }}
3942
</NcActionRouter>
4043
<NcActionButton
41-
v-if="!isArchived"
44+
v-if="!isArchived && !readOnly"
4245
close-after-click
4346
@click="onShareForm">
4447
<template #icon>
@@ -47,6 +50,7 @@
4750
{{ t('forms', 'Share form') }}
4851
</NcActionButton>
4952
<NcActionRouter
53+
v-if="canSeeResults"
5054
close-after-click
5155
exact
5256
:to="{ name: 'results', params: { hash: form.hash } }"
@@ -62,10 +66,11 @@
6266
</template>
6367
{{ t('forms', 'Copy form') }}
6468
</NcActionButton>
65-
<NcActionSeparator v-if="canEdit" />
69+
<NcActionSeparator v-if="canEdit && !readOnly" />
6670
<NcActionButton
67-
v-if="canEdit"
71+
v-if="canEdit && !readOnly"
6872
close-after-click
73+
:disabled="isFormLocked"
6974
@click="onToggleArchive">
7075
<template #icon>
7176
<IconArchiveOff v-if="isArchived" :size="20" />
@@ -78,8 +83,9 @@
7883
}}
7984
</NcActionButton>
8085
<NcActionButton
81-
v-if="canEdit"
86+
v-if="canEdit && !readOnly"
8287
close-after-click
88+
:disabled="isFormLocked"
8389
@click="showDeleteDialog = true">
8490
<template #icon>
8591
<IconDelete :size="20" />
@@ -100,6 +106,7 @@
100106
</template>
101107

102108
<script>
109+
import { getCurrentUser } from '@nextcloud/auth'
103110
import { generateOcsUrl } from '@nextcloud/router'
104111
import { showError } from '@nextcloud/dialogs'
105112
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
@@ -190,6 +197,14 @@ export default {
190197
)
191198
},
192199
200+
canSeeResults() {
201+
return (
202+
this.form.permissions.includes(
203+
this.PERMISSION_TYPES.PERMISSION_RESULTS,
204+
) || this.form.submissionCount > 0
205+
)
206+
},
207+
193208
/**
194209
* Check if form is current form and set active
195210
*/
@@ -211,6 +226,17 @@ export default {
211226
return this.form.expires && moment().unix() > this.form.expires
212227
},
213228
229+
/**
230+
* Check if form is locked
231+
*/
232+
isFormLocked() {
233+
return (
234+
this.form.lockedUntil === 0
235+
|| (this.form.lockedUntil > moment().unix()
236+
&& this.form.lockedBy !== getCurrentUser().uid)
237+
)
238+
},
239+
214240
/**
215241
* Return form title, or placeholder if not set
216242
*

src/components/PillMenu.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
:key="option.id"
1111
:aria-label="isMobile ? option.ariaLabel : null"
1212
:checked="active.id"
13-
:disabled="disabled"
13+
:disabled="disabled || option.disabled"
1414
class="pill-menu__toggle"
1515
:class="{ 'pill-menu__toggle--icon-only': isMobile && option.icon }"
1616
button-variant

src/components/SidebarTabs/SettingsSidebarTab.vue

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,31 @@
55

66
<template>
77
<div class="sidebar-tabs__content">
8+
<NcNoteCard
9+
v-if="locked"
10+
type="info"
11+
:heading="t('forms', 'Form is locked')"
12+
:text="
13+
t('forms', 'Lock by {lockedBy}, expires: {lockedUntil}', {
14+
lockedBy: form.lockedBy ? form.lockedBy : form.ownerId,
15+
lockedUntil:
16+
lockedUntil === '' ? t('forms', 'never') : lockedUntil,
17+
})
18+
" />
19+
<NcButton
20+
v-if="locked && isCurrentUserOwner"
21+
wide
22+
@click="onFormLockChange(false)">
23+
<template #icon>
24+
<NcIconSvgWrapper
25+
:svg="svgLockOpen"
26+
:name="t('forms', 'Open lock')" />
27+
</template>
28+
{{ t('forms', 'Unlock form') }}
29+
</NcButton>
830
<NcCheckboxRadioSwitch
931
:checked="form.isAnonymous"
10-
:disabled="formArchived"
32+
:disabled="formArchived || locked"
1133
type="switch"
1234
@update:checked="onAnonChange">
1335
<!-- TRANSLATORS Checkbox to select whether responses will be stored anonymously or not -->
@@ -16,21 +38,21 @@
1638
<NcCheckboxRadioSwitch
1739
v-tooltip="disableSubmitMultipleExplanation"
1840
:checked="submitMultiple"
19-
:disabled="disableSubmitMultiple || formArchived"
41+
:disabled="disableSubmitMultiple || formArchived || locked"
2042
type="switch"
2143
@update:checked="onSubmitMultipleChange">
2244
{{ t('forms', 'Allow multiple responses per person') }}
2345
</NcCheckboxRadioSwitch>
2446
<NcCheckboxRadioSwitch
2547
:model-value="form.allowEditSubmissions"
26-
:disabled="formArchived"
48+
:disabled="formArchived || locked"
2749
type="switch"
2850
@update:model-value="onAllowEditSubmissionsChange">
2951
{{ t('forms', 'Allow editing own responses') }}
3052
</NcCheckboxRadioSwitch>
3153
<NcCheckboxRadioSwitch
3254
:checked="formExpires"
33-
:disabled="formArchived"
55+
:disabled="formArchived || locked"
3456
type="switch"
3557
@update:checked="onFormExpiresChange">
3658
{{ t('forms', 'Set expiration date') }}
@@ -39,6 +61,7 @@
3961
<NcDateTimePicker
4062
id="expiresDatetimePicker"
4163
:clearable="false"
64+
:disabled="locked"
4265
:disabled-date="notBeforeToday"
4366
:disabled-time="notBeforeNow"
4467
:editable="false"
@@ -50,14 +73,15 @@
5073
@change="onExpirationDateChange" />
5174
<NcCheckboxRadioSwitch
5275
:checked="form.showExpiration"
76+
:disabled="locked"
5377
type="switch"
5478
@update:checked="onShowExpirationChange">
5579
{{ t('forms', 'Show expiration date on form') }}
5680
</NcCheckboxRadioSwitch>
5781
</div>
5882
<NcCheckboxRadioSwitch
5983
:checked="formClosed"
60-
:disabled="formArchived"
84+
:disabled="formArchived || locked"
6185
aria-describedby="forms-settings__close-form"
6286
type="switch"
6387
@update:checked="onFormClosedChange">
@@ -66,9 +90,21 @@
6690
<p id="forms-settings__close-form" class="settings-hint">
6791
{{ t('forms', 'Closed forms do not accept new submissions.') }}
6892
</p>
93+
<NcCheckboxRadioSwitch
94+
:model-value="isFormLockedPermanently"
95+
:disabled="
96+
formArchived
97+
|| (locked && form.lockedUntil !== 0)
98+
|| !isCurrentUserOwner
99+
"
100+
type="switch"
101+
@update:model-value="onFormLockChange">
102+
{{ t('forms', 'Lock form permanently') }}
103+
</NcCheckboxRadioSwitch>
69104
<NcCheckboxRadioSwitch
70105
:checked="formArchived"
71106
aria-describedby="forms-settings__archive-form"
107+
:disabled="locked"
72108
type="switch"
73109
@update:checked="onFormArchivedChange">
74110
{{ t('forms', 'Archive form') }}
@@ -83,7 +119,7 @@
83119
</p>
84120
<NcCheckboxRadioSwitch
85121
:checked="hasCustomSubmissionMessage"
86-
:disabled="formArchived"
122+
:disabled="formArchived || locked"
87123
type="switch"
88124
@update:checked="onUpdateHasCustomSubmissionMessage">
89125
{{ t('forms', 'Custom submission message') }}
@@ -103,6 +139,7 @@
103139
aria-describedby="forms-submission-message-description"
104140
:aria-label="t('forms', 'Custom submission message')"
105141
:value="form.submissionMessage"
142+
:disabled="locked"
106143
:maxlength="maxStringLengths.submissionMessage"
107144
:placeholder="
108145
t(
@@ -132,25 +169,33 @@
132169
</div>
133170
</div>
134171

135-
<TransferOwnership :form="form" />
172+
<TransferOwnership :locked="locked" :form="form" />
136173
</div>
137174
</template>
138175

139176
<script>
177+
import { getCurrentUser } from '@nextcloud/auth'
140178
import moment from '@nextcloud/moment'
179+
import NcButton from '@nextcloud/vue/components/NcButton'
141180
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
142181
import NcDateTimePicker from '@nextcloud/vue/components/NcDateTimePicker'
182+
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
183+
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
143184
import ShareTypes from '../../mixins/ShareTypes.js'
144185
import TransferOwnership from './TransferOwnership.vue'
145186
146187
import { directive as ClickOutside } from 'v-click-outside'
147188
import { loadState } from '@nextcloud/initial-state'
148189
import { FormState } from '../../models/Constants.ts'
190+
import svgLockOpen from '../../../img/lock_open.svg?raw'
149191
150192
export default {
151193
components: {
194+
NcButton,
152195
NcCheckboxRadioSwitch,
153196
NcDateTimePicker,
197+
NcIconSvgWrapper,
198+
NcNoteCard,
154199
TransferOwnership,
155200
},
156201
@@ -167,6 +212,16 @@ export default {
167212
type: Object,
168213
required: true,
169214
},
215+
216+
locked: {
217+
type: Boolean,
218+
required: true,
219+
},
220+
221+
lockedUntil: {
222+
type: String,
223+
default: '',
224+
},
170225
},
171226
172227
data() {
@@ -178,10 +233,19 @@ export default {
178233
maxStringLengths: loadState('forms', 'maxStringLengths'),
179234
/** If custom submission message is shown as input or rendered markdown */
180235
editMessage: false,
236+
svgLockOpen,
181237
}
182238
},
183239
184240
computed: {
241+
isCurrentUserOwner() {
242+
return getCurrentUser().uid === this.form.ownerId
243+
},
244+
245+
isFormLockedPermanently() {
246+
return this.locked && this.form.lockedUntil === 0
247+
},
248+
185249
/**
186250
* If the form has a custom submission message or the user wants to add one (settings switch)
187251
*/
@@ -297,6 +361,10 @@ export default {
297361
)
298362
},
299363
364+
onFormLockChange(locked) {
365+
this.$emit('update:formProp', 'lockedUntil', locked ? 0 : null)
366+
},
367+
300368
onFormArchivedChange(isArchived) {
301369
this.$emit(
302370
'update:formProp',
@@ -386,7 +454,6 @@ export default {
386454
.sidebar-tabs__content {
387455
display: flex;
388456
flex-direction: column;
389-
gap: 8px;
390457
}
391458
.submission-message {
392459
&__description {

src/components/SidebarTabs/SharingSearchDiv.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
:clear-search-on-select="false"
1010
:close-on-select="false"
1111
:loading="showLoadingCircle"
12+
:disabled="locked"
1213
:get-option-key="(option) => option.key"
1314
:options="options"
1415
:placeholder="t('forms', 'Search for user, group or team …')"
@@ -46,6 +47,10 @@ export default {
4647
type: Boolean,
4748
default: false,
4849
},
50+
locked: {
51+
type: Boolean,
52+
required: true,
53+
},
4954
},
5055
5156
computed: {

src/components/SidebarTabs/SharingShareDiv.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,24 @@
1818
<NcActionCaption :name="t('forms', 'Permissions')" />
1919
<NcActionCheckbox
2020
:model-value="canEditForm"
21+
:disabled="locked"
2122
@update:model-value="updatePermissionEdit">
2223
{{ t('forms', 'Edit form') }}
2324
</NcActionCheckbox>
2425
<NcActionCheckbox
2526
:model-value="canAccessResults"
27+
:disabled="locked"
2628
@update:model-value="updatePermissionResults">
2729
{{ t('forms', 'View responses') }}
2830
</NcActionCheckbox>
2931
<NcActionCheckbox
3032
:model-value="canDeleteResults"
31-
:disabled="!canAccessResults"
33+
:disabled="!canAccessResults || locked"
3234
@update:model-value="updatePermissionDeleteResults">
3335
{{ t('forms', 'Delete responses') }}
3436
</NcActionCheckbox>
3537
<NcActionSeparator />
36-
<NcActionButton @click="removeShare">
38+
<NcActionButton :disabled="locked" @click="removeShare">
3739
<template #icon>
3840
<IconClose :size="20" />
3941
</template>
@@ -73,6 +75,11 @@ export default {
7375
type: Object,
7476
required: true,
7577
},
78+
79+
locked: {
80+
type: Boolean,
81+
required: true,
82+
},
7683
},
7784
7885
computed: {

0 commit comments

Comments
 (0)