Skip to content

Commit 71cb2d3

Browse files
feat: add preserve order toggle and view diagram button
Add UI controls in RequestSignatureTab: - Preserve signing order toggle switch - View signing order diagram button - Modal with SigningOrderDiagram component - Sync preserve order state with file changes Signed-off-by: Vitor Mattos <[email protected]>
1 parent 4cfe667 commit 71cb2d3

1 file changed

Lines changed: 154 additions & 12 deletions

File tree

src/Components/RightSidebar/RequestSignatureTab.vue

Lines changed: 154 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@
1515
@click="addSigner">
1616
{{ t('libresign', 'Add signer') }}
1717
</NcButton>
18+
<NcCheckboxRadioSwitch v-if="showPreserveOrder"
19+
v-model="preserveOrder"
20+
type="switch"
21+
@update:checked="onPreserveOrderChange">
22+
{{ t('libresign', 'Preserve signing order') }}
23+
</NcCheckboxRadioSwitch>
24+
<NcButton v-if="showViewOrderButton"
25+
type="tertiary"
26+
@click="showOrderDiagram = true">
27+
<template #icon>
28+
<ChartGantt :size="20" />
29+
</template>
30+
{{ t('libresign', 'View signing order') }}
31+
</NcButton>
1832
<Signers event="libresign:edit-signer"
1933
@signing-order-changed="debouncedSave">
2034
<template #actions="{signer, closeActions}">
@@ -192,6 +206,18 @@
192206
</NcButton>
193207
</template>
194208
</NcDialog>
209+
<NcDialog v-if="showOrderDiagram"
210+
:name="t('libresign', 'Signing order diagram')"
211+
size="large"
212+
@closing="showOrderDiagram = false">
213+
<SigningOrderDiagram :signers="filesStore.getFile()?.signers || []"
214+
:sender-name="currentUserDisplayName" />
215+
<template #actions>
216+
<NcButton @click="showOrderDiagram = false">
217+
{{ t('libresign', 'Close') }}
218+
</NcButton>
219+
</template>
220+
</NcDialog>
195221
</div>
196222
</template>
197223
<script>
@@ -200,11 +226,13 @@ import debounce from 'debounce'
200226
201227
import svgAccount from '@mdi/svg/svg/account.svg?raw'
202228
import svgEmail from '@mdi/svg/svg/email.svg?raw'
229+
import svgInfo from '@mdi/svg/svg/information-outline.svg?raw'
203230
import svgSms from '@mdi/svg/svg/message-processing.svg?raw'
204231
import svgWhatsapp from '@mdi/svg/svg/whatsapp.svg?raw'
205232
import svgXmpp from '@mdi/svg/svg/xmpp.svg?raw'
206233
207234
import Bell from 'vue-material-design-icons/Bell.vue'
235+
import ChartGantt from 'vue-material-design-icons/ChartGantt.vue'
208236
import Delete from 'vue-material-design-icons/Delete.vue'
209237
import Draw from 'vue-material-design-icons/Draw.vue'
210238
import FileDocument from 'vue-material-design-icons/FileDocument.vue'
@@ -227,15 +255,17 @@ import NcActions from '@nextcloud/vue/components/NcActions'
227255
import NcAppSidebar from '@nextcloud/vue/components/NcAppSidebar'
228256
import NcAppSidebarTab from '@nextcloud/vue/components/NcAppSidebarTab'
229257
import NcButton from '@nextcloud/vue/components/NcButton'
258+
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
230259
import NcDialog from '@nextcloud/vue/components/NcDialog'
231260
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
232261
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
233262
import NcModal from '@nextcloud/vue/components/NcModal'
234263
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
235264
236265
import IdentifySigner from '../Request/IdentifySigner.vue'
237-
import VisibleElements from '../Request/VisibleElements.vue'
238266
import Signers from '../Signers/Signers.vue'
267+
import SigningOrderDiagram from '../SigningOrder/SigningOrderDiagram.vue'
268+
import VisibleElements from '../Request/VisibleElements.vue'
239269
240270
import svgSignal from '../../../img/logo-signal-app.svg?raw'
241271
import svgTelegram from '../../../img/logo-telegram-app.svg?raw'
@@ -262,28 +292,31 @@ export default {
262292
name: 'RequestSignatureTab',
263293
mixins: [signingOrderMixin],
264294
components: {
295+
Bell,
296+
ChartGantt,
297+
Delete,
298+
Draw,
299+
FileDocument,
300+
IdentifySigner,
301+
Information,
302+
MessageText,
265303
NcActionButton,
266304
NcActionInput,
267305
NcActions,
268306
NcAppSidebar,
269307
NcAppSidebarTab,
270308
NcButton,
309+
NcCheckboxRadioSwitch,
310+
NcDialog,
271311
NcIconSvgWrapper,
272312
NcLoadingIcon,
273313
NcModal,
274314
NcNoteCard,
275-
NcDialog,
276-
Bell,
277-
Delete,
278-
Draw,
279-
FileDocument,
280-
Information,
281-
MessageText,
282315
OrderNumericAscending,
283316
Pencil,
284317
Send,
285318
Signers,
286-
IdentifySigner,
319+
SigningOrderDiagram,
287320
VisibleElements,
288321
},
289322
props: {
@@ -311,23 +344,61 @@ export default {
311344
showConfirmRequestSigner: false,
312345
selectedSigner: null,
313346
activeTab: '',
347+
preserveOrder: false,
348+
showOrderDiagram: false,
349+
infoIcon: svgInfo,
350+
adminSignatureFlow: '',
351+
lastSyncedFileId: null,
314352
}
315353
},
316354
computed: {
317355
signatureFlow() {
318356
const file = this.filesStore.getFile()
319-
return file?.signatureFlow ?? 'parallel'
357+
let flow = file?.signatureFlow
358+
359+
if (typeof flow === 'number') {
360+
const flowMap = { 0: 'none', 1: 'parallel', 2: 'ordered_numeric' }
361+
flow = flowMap[flow]
362+
}
363+
364+
if (flow && flow !== 'none') {
365+
return flow
366+
}
367+
if (this.adminSignatureFlow && this.adminSignatureFlow !== 'none') {
368+
return this.adminSignatureFlow
369+
}
370+
return 'parallel'
371+
},
372+
isAdminFlowForced() {
373+
return this.adminSignatureFlow && this.adminSignatureFlow !== 'none'
320374
},
321375
isOrderedNumeric() {
322376
return this.signatureFlow === 'ordered_numeric'
323377
},
378+
showSigningOrderOptions() {
379+
return this.hasSigners && this.filesStore.canSave() && !this.isAdminFlowForced
380+
},
381+
showPreserveOrder() {
382+
return this.hasSigners && this.filesStore.canSave() && !this.isAdminFlowForced
383+
},
384+
showViewOrderButton() {
385+
return this.isOrderedNumeric && this.totalSigners > 1 && this.hasSigners
386+
},
387+
shouldShowOrderedOptions() {
388+
return this.isOrderedNumeric && this.totalSigners > 1
389+
},
390+
currentUserDisplayName() {
391+
return OC.getCurrentUser()?.displayName || ''
392+
},
324393
showDocMdpWarning() {
325394
return this.filesStore.isDocMdpNoChangesAllowed() && !this.filesStore.canAddSigner()
326395
},
327396
canEditSigningOrder() {
328397
return (signer) => {
398+
const minSigners = this.isAdminFlowForced ? 1 : 2
399+
329400
return this.isOrderedNumeric
330-
&& this.totalSigners > 1
401+
&& this.totalSigners >= minSigners
331402
&& this.filesStore.canSave()
332403
&& !signer.signed
333404
}
@@ -490,12 +561,25 @@ export default {
490561
signers(signers) {
491562
this.init(signers)
492563
},
564+
'filesStore.selectedNodeId': {
565+
handler(newFileId, oldFileId) {
566+
if (newFileId && newFileId !== this.lastSyncedFileId) {
567+
this.syncPreserveOrderWithFile()
568+
this.lastSyncedFileId = newFileId
569+
}
570+
},
571+
immediate: true,
572+
},
493573
},
494574
async mounted() {
495575
subscribe('libresign:edit-signer', this.editSigner)
496576
this.filesStore.disableIdentifySigner()
497577
498578
this.activeTab = this.userConfigStore.signer_identify_tab || ''
579+
580+
this.adminSignatureFlow = loadState('libresign', 'signature_flow', 'none')
581+
582+
this.syncPreserveOrderWithFile()
499583
},
500584
beforeUnmount() {
501585
unsubscribe('libresign:edit-signer')
@@ -506,7 +590,11 @@ export default {
506590
507591
this.debouncedSave = debounce(async () => {
508592
try {
509-
await this.filesStore.saveWithVisibleElements({ visibleElements: [] })
593+
const file = this.filesStore.getFile()
594+
await this.filesStore.saveWithVisibleElements({
595+
visibleElements: [],
596+
signatureFlow: file?.signatureFlow,
597+
})
510598
} catch (error) {
511599
if (error.response?.data?.ocs?.data?.message) {
512600
showError(error.response.data.ocs.data.message)
@@ -521,6 +609,56 @@ export default {
521609
}, 500)
522610
},
523611
methods: {
612+
onPreserveOrderChange(value) {
613+
this.preserveOrder = value
614+
const file = this.filesStore.getFile()
615+
616+
if (value) {
617+
if (file?.signers) {
618+
file.signers.forEach((signer, index) => {
619+
if (!signer.signingOrder) {
620+
this.$set(signer, 'signingOrder', index + 1)
621+
}
622+
})
623+
}
624+
if (file) {
625+
this.$set(file, 'signatureFlow', 'ordered_numeric')
626+
}
627+
} else {
628+
if (!this.isAdminFlowForced) {
629+
if (file?.signers) {
630+
file.signers.forEach(signer => {
631+
if (!signer.signed) {
632+
this.$set(signer, 'signingOrder', 1)
633+
}
634+
})
635+
}
636+
if (file) {
637+
this.$set(file, 'signatureFlow', 'parallel')
638+
}
639+
}
640+
}
641+
642+
this.debouncedSave()
643+
},
644+
645+
syncPreserveOrderWithFile() {
646+
const file = this.filesStore.getFile()
647+
if (!file) {
648+
this.preserveOrder = false
649+
return
650+
}
651+
652+
const flow = file.signatureFlow
653+
654+
this.lastSyncedFileId = this.filesStore.selectedNodeId
655+
656+
if ((flow === 'ordered_numeric' || flow === 2) && !this.isAdminFlowForced) {
657+
this.preserveOrder = true
658+
} else {
659+
this.preserveOrder = false
660+
}
661+
},
524662
getSvgIcon(name) {
525663
return iconMap[`svg${name.charAt(0).toUpperCase() + name.slice(1)}`] || iconMap.svgAccount
526664
},
@@ -789,6 +927,10 @@ export default {
789927
</script>
790928
<style lang="scss" scoped>
791929
930+
:deep(.checkbox-radio-switch) {
931+
margin: 8px 0;
932+
}
933+
792934
.action-buttons {
793935
display: flex;
794936
flex-direction: column;

0 commit comments

Comments
 (0)