Skip to content

Commit 9688265

Browse files
committed
feat: add manual signing order input with auto-save
Add NcActionInput for manual signing order entry with dual-mode behavior: updateSigningOrder for visual reordering during typing, confirmSigningOrder for normalization and persistence on submit/blur. Implement debounced auto-save (1000ms) after drag-and-drop or manual order changes. Listen to signing-order-changed event from Signers component using Vue $emit pattern. Signed-off-by: Vitor Mattos <[email protected]>
1 parent b15f95c commit 9688265

1 file changed

Lines changed: 107 additions & 2 deletions

File tree

src/Components/RightSidebar/RequestSignatureTab.vue

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,20 @@
99
@click="addSigner">
1010
{{ t('libresign', 'Add signer') }}
1111
</NcButton>
12-
<Signers event="libresign:edit-signer">
13-
<template #actions="{signer}">
12+
<Signers event="libresign:edit-signer"
13+
@signing-order-changed="debouncedSave">
14+
<template #actions="{signer, closeActions}">
15+
<NcActionInput v-if="isOrderedNumeric && totalSigners > 1 && filesStore.canSave() && !signer.signed"
16+
:label="t('libresign', 'Signing order')"
17+
type="number"
18+
:value="signer.signingOrder || 1"
19+
@update:value="updateSigningOrder(signer, $event)"
20+
@submit="confirmSigningOrder(signer); closeActions()"
21+
@blur="confirmSigningOrder(signer)">
22+
<template #icon>
23+
<OrderNumericAscending :size="20" />
24+
</template>
25+
</NcActionInput>
1426
<NcActionButton v-if="filesStore.canSave() && !signer.signed"
1527
aria-label="Delete"
1628
:close-after-click="true"
@@ -104,6 +116,8 @@
104116
</template>
105117
<script>
106118
119+
import debounce from 'debounce'
120+
107121
import svgAccount from '@mdi/svg/svg/account.svg?raw'
108122
import svgEmail from '@mdi/svg/svg/email.svg?raw'
109123
import svgSms from '@mdi/svg/svg/message-processing.svg?raw'
@@ -113,6 +127,7 @@ import svgXmpp from '@mdi/svg/svg/xmpp.svg?raw'
113127
import Delete from 'vue-material-design-icons/Delete.vue'
114128
import Draw from 'vue-material-design-icons/Draw.vue'
115129
import FileDocument from 'vue-material-design-icons/FileDocument.vue'
130+
import OrderNumericAscending from 'vue-material-design-icons/OrderNumericAscending.vue'
116131
import Pencil from 'vue-material-design-icons/Pencil.vue'
117132
import Send from 'vue-material-design-icons/Send.vue'
118133
@@ -124,6 +139,7 @@ import { loadState } from '@nextcloud/initial-state'
124139
import { generateOcsUrl } from '@nextcloud/router'
125140
126141
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
142+
import NcActionInput from '@nextcloud/vue/components/NcActionInput'
127143
import NcAppSidebar from '@nextcloud/vue/components/NcAppSidebar'
128144
import NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'
129145
import NcButton from '@nextcloud/vue/components/NcButton'
@@ -154,10 +170,14 @@ const iconMap = {
154170
svgXmpp,
155171
}
156172
173+
import signingOrderMixin from '../../mixins/signingOrderMixin.js'
174+
157175
export default {
158176
name: 'RequestSignatureTab',
177+
mixins: [signingOrderMixin],
159178
components: {
160179
NcActionButton,
180+
NcActionInput,
161181
NcAppSidebar,
162182
NcAppSidebarTab,
163183
NcButton,
@@ -168,6 +188,7 @@ export default {
168188
Delete,
169189
Draw,
170190
FileDocument,
191+
OrderNumericAscending,
171192
Pencil,
172193
Send,
173194
Signers,
@@ -194,9 +215,13 @@ export default {
194215
document: {},
195216
hasInfo: false,
196217
methods: [],
218+
signatureFlow: loadState('libresign', 'signature_flow', 'parallel'),
197219
}
198220
},
199221
computed: {
222+
isOrderedNumeric() {
223+
return this.signatureFlow === 'ordered_numeric'
224+
},
200225
showSaveButton() {
201226
if (!this.filesStore.canSave()) {
202227
return false
@@ -223,6 +248,9 @@ export default {
223248
hasSigners() {
224249
return this.filesStore.hasSigners(this.filesStore.getFile())
225250
},
251+
totalSigners() {
252+
return this.filesStore.getFile()?.signers?.length || 0
253+
},
226254
fileName() {
227255
return this.filesStore.getFile()?.name ?? ''
228256
},
@@ -245,6 +273,18 @@ export default {
245273
created() {
246274
this.$set(this, 'methods', loadState('libresign', 'identify_methods'))
247275
this.$set(this, 'document', loadState('libresign', 'file_info', {}))
276+
277+
this.debouncedSave = debounce(async () => {
278+
try {
279+
await this.filesStore.saveWithVisibleElements({ visibleElements: [] })
280+
} catch (error) {
281+
if (error.response?.data?.ocs?.data?.message) {
282+
showError(error.response.data.ocs.data.message)
283+
} else if (error.response?.data?.ocs?.data?.errors) {
284+
error.response.data.ocs.data.errors.forEach(error => showError(error.message))
285+
}
286+
}
287+
}, 1000)
248288
},
249289
methods: {
250290
getSvgIcon(name) {
@@ -277,6 +317,71 @@ export default {
277317
this.signerToEdit = signer
278318
this.filesStore.enableIdentifySigner()
279319
},
320+
updateSigningOrder(signer, value) {
321+
const order = parseInt(value, 10)
322+
const file = this.filesStore.getFile()
323+
324+
if (isNaN(order)) {
325+
return
326+
}
327+
328+
const currentIndex = file.signers.findIndex(s => s.identify === signer.identify)
329+
if (currentIndex === -1) {
330+
return
331+
}
332+
333+
this.$set(file.signers[currentIndex], 'signingOrder', order)
334+
335+
const sortedSigners = [...file.signers].sort((a, b) => {
336+
const orderA = a.signingOrder || 999
337+
const orderB = b.signingOrder || 999
338+
if (orderA === orderB) {
339+
return 0
340+
}
341+
return orderA - orderB
342+
})
343+
344+
this.$set(file, 'signers', sortedSigners)
345+
},
346+
confirmSigningOrder(signer) {
347+
const file = this.filesStore.getFile()
348+
349+
const currentIndex = file.signers.findIndex(s => s.identify === signer.identify)
350+
if (currentIndex === -1) {
351+
return
352+
}
353+
354+
const order = file.signers[currentIndex].signingOrder
355+
const oldOrder = signer.signingOrder
356+
357+
for (let i = 0; i < file.signers.length; i++) {
358+
if (i === currentIndex) continue
359+
360+
const currentItemOrder = file.signers[i].signingOrder
361+
362+
if (order < oldOrder) {
363+
if (currentItemOrder >= order && currentItemOrder < oldOrder) {
364+
this.$set(file.signers[i], 'signingOrder', currentItemOrder + 1)
365+
}
366+
} else if (order > oldOrder) {
367+
if (currentItemOrder > oldOrder && currentItemOrder <= order) {
368+
this.$set(file.signers[i], 'signingOrder', currentItemOrder - 1)
369+
}
370+
}
371+
}
372+
373+
const sortedSigners = [...file.signers].sort((a, b) => {
374+
const orderA = a.signingOrder || 999
375+
const orderB = b.signingOrder || 999
376+
return orderA - orderB
377+
})
378+
379+
this.normalizeSigningOrders(sortedSigners)
380+
381+
this.$set(file, 'signers', sortedSigners)
382+
383+
this.debouncedSave()
384+
},
280385
async sendNotify(signer) {
281386
const body = {
282387
fileId: this.filesStore.selectedNodeId,

0 commit comments

Comments
 (0)