Skip to content

Commit b15f95c

Browse files
committed
feat: implement drag-and-drop reordering for signers
Integrate vuedraggable to enable drag-and-drop reordering when in ordered_numeric mode. Track originalOrders during drag operations, recalculate signingOrder using shared mixin logic, emit signing-order-changed event to trigger auto-save. Include CSS animations and visual feedback for drag states. Signed-off-by: Vitor Mattos <[email protected]>
1 parent c9dba8d commit b15f95c

1 file changed

Lines changed: 115 additions & 3 deletions

File tree

src/Components/Signers/Signers.vue

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,54 @@
33
- SPDX-License-Identifier: AGPL-3.0-or-later
44
-->
55
<template>
6-
<ul>
6+
<draggable v-if="isOrderedNumeric && canReorder"
7+
v-model="sortableSigners"
8+
tag="ul"
9+
handle=".list-item"
10+
class="signers-list"
11+
chosenClass="signer-dragging"
12+
dragClass="signer-drag-ghost"
13+
@start="onDragStart"
14+
@end="onDragEnd">
15+
<transition-group name="signer-list" tag="div">
16+
<Signer v-for="(signer, index) in sortableSigners"
17+
:key="signer.identify || index"
18+
:current-signer="index"
19+
:event="event"
20+
:draggable="!signer.signed">
21+
<template #actions="{closeActions}">
22+
<slot name="actions" :signer="signer" :closeActions="closeActions" />
23+
</template>
24+
</Signer>
25+
</transition-group>
26+
</draggable>
27+
<ul v-else>
728
<Signer v-for="(signer, index) in signers"
8-
:key="index"
29+
:key="signer.identify || index"
930
:current-signer="index"
1031
:event="event">
11-
<slot v-bind="{signer}" slot="actions" name="actions" />
32+
<template #actions="{closeActions}">
33+
<slot name="actions" :signer="signer" :closeActions="closeActions" />
34+
</template>
1235
</Signer>
1336
</ul>
1437
</template>
1538
<script>
39+
import { loadState } from '@nextcloud/initial-state'
40+
41+
import draggable from 'vuedraggable'
42+
1643
import Signer from './Signer.vue'
44+
import signingOrderMixin from '../../mixins/signingOrderMixin.js'
1745
1846
import { useFilesStore } from '../../store/files.js'
1947
2048
export default {
2149
name: 'Signers',
50+
mixins: [signingOrderMixin],
2251
components: {
2352
Signer,
53+
draggable,
2454
},
2555
props: {
2656
event: {
@@ -33,10 +63,92 @@ export default {
3363
const filesStore = useFilesStore()
3464
return { filesStore }
3565
},
66+
data() {
67+
return {
68+
originalOrders: [],
69+
}
70+
},
3671
computed: {
3772
signers() {
3873
return this.filesStore.getFile().signers
3974
},
75+
sortableSigners: {
76+
get() {
77+
return this.signers
78+
},
79+
set(value) {
80+
const file = this.filesStore.getFile()
81+
this.$set(file, 'signers', value)
82+
},
83+
},
84+
isOrderedNumeric() {
85+
return loadState('libresign', 'signature_flow', 'parallel') === 'ordered_numeric'
86+
},
87+
canReorder() {
88+
return this.filesStore.canSave() && this.signers.length > 1
89+
},
90+
},
91+
methods: {
92+
onDragStart() {
93+
const file = this.filesStore.getFile()
94+
this.originalOrders = file.signers.map(s => s.signingOrder)
95+
},
96+
onDragEnd(evt) {
97+
const { oldIndex, newIndex } = evt
98+
if (oldIndex === newIndex) {
99+
return
100+
}
101+
102+
const file = this.filesStore.getFile()
103+
const signers = file.signers
104+
105+
this.recalculateSigningOrders(signers, newIndex, this.originalOrders, oldIndex)
106+
107+
const sorted = [...file.signers].sort((a, b) => {
108+
return (a.signingOrder || 999) - (b.signingOrder || 999)
109+
})
110+
this.$set(file, 'signers', sorted)
111+
112+
this.$emit('signing-order-changed')
113+
},
40114
},
41115
}
42116
</script>
117+
118+
<style lang="scss" scoped>
119+
.signers-list {
120+
list-style: none;
121+
padding: 0;
122+
}
123+
124+
:deep(.signer-dragging) {
125+
opacity: 0.5;
126+
background: var(--color-background-hover);
127+
border-radius: var(--border-radius-large);
128+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
129+
}
130+
131+
:deep(.signer-drag-ghost) {
132+
opacity: 0.8;
133+
background: var(--color-primary-element-light);
134+
border: 2px dashed var(--color-primary-element);
135+
border-radius: var(--border-radius-large);
136+
}
137+
138+
.signer-list {
139+
&-move {
140+
transition: transform 0.3s ease;
141+
}
142+
143+
&-enter-active,
144+
&-leave-active {
145+
transition: all 0.3s ease;
146+
}
147+
148+
&-enter-from,
149+
&-leave-to {
150+
opacity: 0;
151+
transform: translateX(30px);
152+
}
153+
}
154+
</style>

0 commit comments

Comments
 (0)