@fickou/quasar-workflow 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +535 -0
  3. package/dist/composables/useWorkflow.d.ts +108 -0
  4. package/dist/composables/useWorkflow.js +183 -0
  5. package/dist/composables/useWorkflow.js.map +1 -0
  6. package/dist/composables/useWorkflowAdmin.d.ts +51 -0
  7. package/dist/composables/useWorkflowAdmin.js +140 -0
  8. package/dist/composables/useWorkflowAdmin.js.map +1 -0
  9. package/dist/composables/useWorkflowDashboard.d.ts +72 -0
  10. package/dist/composables/useWorkflowDashboard.js +40 -0
  11. package/dist/composables/useWorkflowDashboard.js.map +1 -0
  12. package/dist/composables/useWorkflowDelegation.d.ts +76 -0
  13. package/dist/composables/useWorkflowDelegation.js +87 -0
  14. package/dist/composables/useWorkflowDelegation.js.map +1 -0
  15. package/dist/composables/useWorkflowFieldControl.d.ts +19 -0
  16. package/dist/composables/useWorkflowFieldControl.js +111 -0
  17. package/dist/composables/useWorkflowFieldControl.js.map +1 -0
  18. package/dist/composables/useWorkflowStats.d.ts +21 -0
  19. package/dist/composables/useWorkflowStats.js +87 -0
  20. package/dist/composables/useWorkflowStats.js.map +1 -0
  21. package/dist/composables/useWorkflowWebSocket.d.ts +26 -0
  22. package/dist/composables/useWorkflowWebSocket.js +140 -0
  23. package/dist/composables/useWorkflowWebSocket.js.map +1 -0
  24. package/dist/directives/vWorkflowField.d.ts +2 -0
  25. package/dist/directives/vWorkflowField.js +59 -0
  26. package/dist/directives/vWorkflowField.js.map +1 -0
  27. package/dist/index.d.ts +23 -0
  28. package/dist/index.js +29 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/plugins/WorkflowPlugin.d.ts +6 -0
  31. package/dist/plugins/WorkflowPlugin.js +36 -0
  32. package/dist/plugins/WorkflowPlugin.js.map +1 -0
  33. package/dist/types/index.d.ts +47 -0
  34. package/dist/types/index.js +3 -0
  35. package/dist/types/index.js.map +1 -0
  36. package/package.json +63 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 fickou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,535 @@
1
+ # @fickou/quasar-workflow
2
+
3
+ Composants et composables Vue 3 pour intégrer le moteur de workflow dans une application **Quasar v2**.
4
+
5
+ Dépend uniquement de l'API REST exposée par `adonis-workflow`. Aucune dépendance directe sur le backend.
6
+
7
+ ---
8
+
9
+ ## Table des matières
10
+
11
+ 1. [Installation](#1-installation)
12
+ 2. [Enregistrement du plugin](#2-enregistrement-du-plugin)
13
+ 3. [Usage de base — formulaire avec workflow](#3-usage-de-base--formulaire-avec-workflow)
14
+ 4. [Directive `v-workflow-field`](#4-directive-v-workflow-field)
15
+ 5. [WorkflowActionBar — boutons d'action](#5-workflowactionbar--boutons-daction)
16
+ 6. [WorkflowStepper — visualisation](#6-workflowstepper--visualisation)
17
+ 7. [WorkflowHistory — journal](#7-workflowhistory--journal)
18
+ 8. [useWorkflow — composable principal](#8-useworkflow--composable-principal)
19
+ 9. [useWorkflowWebSocket — temps réel](#9-useworkflowwebsocket--temps-réel)
20
+ 10. [useWorkflowFieldControl — contrôle des champs](#10-useworkflowfieldcontrol--contrôle-des-champs)
21
+ 11. [Composants de suivi et monitoring](#11-composants-de-suivi-et-monitoring)
22
+ 12. [Composants d'administration](#12-composants-dadministration)
23
+ 13. [useWorkflowDelegation — délégations](#13-useworkflowdelegation--délégations)
24
+ 14. [useWorkflowStats — statistiques](#14-useworkflowstats--statistiques)
25
+ 15. [Référence des composables](#15-référence-des-composables)
26
+ 16. [Tableau formMode / canDelete](#16-tableau-formmode--candelete)
27
+
28
+ ---
29
+
30
+ ## 1. Installation
31
+
32
+ Ce package s'installe par **copie directe** dans le projet hôte (pas de registry npm).
33
+
34
+ ```bash
35
+ # Via npm (recommandé)
36
+ npm install @fickou/quasar-workflow
37
+
38
+ # Ou via le chemin local (monorepo)
39
+ npm install file:packages/quasar-workflow
40
+ ```
41
+
42
+ Vérifier que les peer dependencies sont présentes :
43
+
44
+ ```json
45
+ "vue": "^3.0.0",
46
+ "quasar": "^2.0.0",
47
+ "axios": "^1.0.0"
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 2. Enregistrement du plugin
53
+
54
+ Créer un fichier boot dédié dans votre projet Quasar :
55
+
56
+ ```typescript
57
+ // src/boot/workflow.ts
58
+ import { boot } from 'quasar/wrappers'
59
+ import { WorkflowPlugin } from '@fickou/quasar-workflow'
60
+
61
+ export default boot(({ app }) => {
62
+ app.use(WorkflowPlugin, {
63
+ // URL de base de l'API workflow (le préfixe doit correspondre à routePrefix dans adonis-workflow)
64
+ apiBase: '/api/workflow',
65
+
66
+ // URL du serveur WebSocket AdonisJS (optionnel — uniquement si @adonisjs/websocket est installé)
67
+ wsUrl: 'ws://localhost:3333',
68
+ })
69
+ })
70
+ ```
71
+
72
+ Déclarer le boot dans `quasar.config.ts` :
73
+
74
+ ```typescript
75
+ // quasar.config.ts
76
+ boot: [
77
+ 'axios',
78
+ 'workflow', // ← ajouter
79
+ ],
80
+ ```
81
+
82
+ Le plugin enregistre automatiquement **tous les composants** (`WorkflowFormGuard`, `WorkflowActionBar`, etc.) et la **directive `v-workflow-field`** de façon globale. Aucun import supplémentaire n'est nécessaire dans vos pages.
83
+
84
+ ---
85
+
86
+ ## 3. Usage de base — formulaire avec workflow
87
+
88
+ Le pattern standard consiste à envelopper votre formulaire dans `WorkflowFormGuard`, qui gère automatiquement le mode du formulaire selon l'état du workflow.
89
+
90
+ ```vue
91
+ <!-- src/pages/InvoicePage.vue -->
92
+ <template>
93
+ <q-page padding>
94
+ <WorkflowFormGuard
95
+ entity-type="invoice"
96
+ :entity-id="invoiceId"
97
+ :current-user-id="currentUser.id"
98
+ @action-executed="onActionExecuted"
99
+ >
100
+ <template #default="{ formMode, canEdit, canDelete, canSubmit, canResubmit, hookRejectionReason }">
101
+
102
+ <!-- Alerte si une action a été bloquée par un hook métier -->
103
+ <q-banner v-if="hookRejectionReason" type="warning" class="q-mb-md">
104
+ {{ hookRejectionReason }}
105
+ </q-banner>
106
+
107
+ <!-- Champs du formulaire — v-workflow-field gère readonly/disable automatiquement -->
108
+ <q-input
109
+ v-workflow-field="'amount'"
110
+ v-model="invoice.amount"
111
+ label="Montant"
112
+ type="number"
113
+ />
114
+
115
+ <q-input
116
+ v-workflow-field="'description'"
117
+ v-model="invoice.description"
118
+ label="Description"
119
+ type="textarea"
120
+ />
121
+
122
+ <!-- Boutons selon le mode -->
123
+ <div class="row q-gutter-sm q-mt-md">
124
+ <q-btn
125
+ v-if="formMode === 'create'"
126
+ label="Créer la facture"
127
+ color="primary"
128
+ @click="createInvoice"
129
+ />
130
+ <q-btn
131
+ v-if="canEdit"
132
+ label="Enregistrer"
133
+ color="primary"
134
+ @click="saveInvoice"
135
+ />
136
+ <q-btn
137
+ v-if="canDelete"
138
+ label="Supprimer"
139
+ color="negative"
140
+ @click="deleteInvoice"
141
+ />
142
+ </div>
143
+
144
+ <!-- Barre d'actions workflow (boutons approve, reject, etc.) -->
145
+ <WorkflowActionBar
146
+ entity-type="invoice"
147
+ :entity-id="invoiceId"
148
+ class="q-mt-md"
149
+ />
150
+
151
+ <!-- Visualisation de l'avancement -->
152
+ <WorkflowStepper
153
+ entity-type="invoice"
154
+ :entity-id="invoiceId"
155
+ class="q-mt-lg"
156
+ />
157
+
158
+ </template>
159
+ </WorkflowFormGuard>
160
+ </q-page>
161
+ </template>
162
+
163
+ <script setup lang="ts">
164
+ import { ref, computed } from 'vue'
165
+ import { useAuthStore } from 'src/stores/auth'
166
+
167
+ const props = defineProps<{ invoiceId: string | null }>()
168
+ const authStore = useAuthStore()
169
+ const currentUser = computed(() => authStore.user)
170
+ const invoice = ref({ amount: 0, description: '' })
171
+
172
+ const onActionExecuted = (action: string) => {
173
+ // Rafraîchir les données après une action workflow
174
+ console.log('Action exécutée :', action)
175
+ }
176
+
177
+ async function createInvoice() { /* ... */ }
178
+ async function saveInvoice() { /* ... */ }
179
+ async function deleteInvoice() { /* ... */ }
180
+ </script>
181
+ ```
182
+
183
+ ### Props de `WorkflowFormGuard`
184
+
185
+ | Prop | Type | Requis | Description |
186
+ |---|---|---|---|
187
+ | `entity-type` | `string` | ✅ | Type d'entité (`invoice`, `purchase_order`…) |
188
+ | `entity-id` | `string \| null` | ✅ | ID du document. `null` → mode création |
189
+ | `current-user-id` | `string` | ✅ | ID de l'utilisateur courant |
190
+
191
+ ### Slot `#default`
192
+
193
+ | Variable | Type | Description |
194
+ |---|---|---|
195
+ | `formMode` | `FormMode` | Mode courant du formulaire |
196
+ | `canEdit` | `boolean` | L'utilisateur peut modifier les champs |
197
+ | `canDelete` | `boolean` | L'utilisateur peut supprimer le document |
198
+ | `canSubmit` | `boolean` | Le workflow peut être démarré |
199
+ | `canResubmit` | `boolean` | Le document peut être resoumis après correction |
200
+ | `hookRejectionReason` | `string \| null` | Message de refus d'un ActionHook |
201
+ | `instance` | `WorkflowInstanceDTO \| null` | Instance de workflow courante |
202
+
203
+ ---
204
+
205
+ ## 4. Directive `v-workflow-field`
206
+
207
+ La directive `v-workflow-field` applique automatiquement `readonly` ou `disable` sur un champ selon les droits de l'étape courante.
208
+
209
+ ```vue
210
+ <!-- readonly si l'étape n'autorise pas la modification du champ -->
211
+ <q-input v-workflow-field="'amount'" v-model="form.amount" />
212
+ <q-select v-workflow-field="'category'" v-model="form.category" :options="categories" />
213
+ ```
214
+
215
+ **Prérequis** : la directive doit être utilisée à l'intérieur d'un `WorkflowFormGuard`. Celui-ci expose via `provide()` la fonction `workflowFieldState` consommée par la directive.
216
+
217
+ Les champs éditables sont définis dans la propriété `editable_fields` de chaque étape de la définition workflow.
218
+
219
+ ---
220
+
221
+ ## 5. WorkflowActionBar — boutons d'action
222
+
223
+ Affiche les boutons d'action disponibles pour l'étape courante (approve, reject, transfer, etc.).
224
+
225
+ ```vue
226
+ <WorkflowActionBar
227
+ entity-type="invoice"
228
+ :entity-id="invoiceId"
229
+ @action-executed="onActionExecuted"
230
+ @hook-rejected="onHookRejected"
231
+ />
232
+ ```
233
+
234
+ ### Props
235
+
236
+ | Prop | Type | Description |
237
+ |---|---|---|
238
+ | `entity-type` | `string` | Type d'entité |
239
+ | `entity-id` | `string \| null` | ID du document |
240
+
241
+ ### Événements émis
242
+
243
+ | Événement | Payload | Description |
244
+ |---|---|---|
245
+ | `action-executed` | `{ action: string }` | Après une action réussie |
246
+ | `hook-rejected` | `{ reason: string }` | Quand un ActionHook bloque |
247
+
248
+ ### Actions affichées automatiquement selon l'étape
249
+
250
+ Les actions sont filtrées selon la configuration `WorkflowStepAction` de l'étape courante. La `WorkflowActionBar` gère automatiquement :
251
+
252
+ - Les **dialogs de saisie de raison** pour les actions qui la requièrent
253
+ - Le **champ "Transférer à"** pour l'action `transfer`
254
+ - Le **verrouillage optimiste** (passage automatique du `version` actuel)
255
+ - Le **bouton Soumettre** (démarrage du workflow) quand pas d'instance
256
+ - Le **bouton Re-soumettre** en mode correction
257
+
258
+ ---
259
+
260
+ ## 6. WorkflowStepper — visualisation
261
+
262
+ Affiche la progression du workflow avec le statut de chaque étape.
263
+
264
+ ```vue
265
+ <WorkflowStepper
266
+ entity-type="invoice"
267
+ :entity-id="invoiceId"
268
+ />
269
+ ```
270
+
271
+ Gère automatiquement les trois topologies :
272
+ - **Séquentielle** : étapes affichées en ligne
273
+ - **Parallèle** : étapes `fork`/`join` affichées côte à côte
274
+ - **Conditionnelle** : étapes skippées affichées en grisé
275
+
276
+ ---
277
+
278
+ ## 7. WorkflowHistory — journal
279
+
280
+ Affiche l'historique complet des actions sous forme de timeline.
281
+
282
+ ```vue
283
+ <WorkflowHistory
284
+ entity-type="invoice"
285
+ :entity-id="invoiceId"
286
+ />
287
+ ```
288
+
289
+ Chaque entrée affiche : action, acteur, date, raison (si présente).
290
+
291
+ ---
292
+
293
+ ## 8. useWorkflow — composable principal
294
+
295
+ Pour un contrôle fin, utiliser le composable directement :
296
+
297
+ ```typescript
298
+ import { useWorkflow } from '@fickou/quasar-workflow'
299
+ import { ref } from 'vue'
300
+
301
+ const entityId = ref<string | null>('inv-123')
302
+
303
+ const {
304
+ instance, // Ref<WorkflowInstanceDTO | null>
305
+ definition, // Ref<WorkflowDefinitionDTO | null>
306
+ loading, // Ref<boolean>
307
+ error, // Ref<string | null>
308
+ hookRejectionReason, // Ref<string | null>
309
+
310
+ fetchInstanceAndDefinition, // () => Promise<void>
311
+ submitWorkflow, // () => Promise<void> — démarre le workflow
312
+ resubmit, // () => Promise<void> — resoumet après correction
313
+ executeAction, // (action, payload) => Promise<void>
314
+ } = useWorkflow('invoice', entityId)
315
+
316
+ // Charger au montage
317
+ await fetchInstanceAndDefinition()
318
+
319
+ // Exécuter une action
320
+ await executeAction('approve', {
321
+ version: instance.value!.steps[0].version,
322
+ reason: 'Conforme au budget',
323
+ })
324
+ ```
325
+
326
+ ---
327
+
328
+ ## 9. useWorkflowWebSocket — temps réel
329
+
330
+ Le WebSocket permet de recevoir les mises à jour en temps réel sans rafraîchir la page.
331
+
332
+ ```typescript
333
+ import { useWorkflowWebSocket } from '@fickou/quasar-workflow'
334
+ import { ref } from 'vue'
335
+
336
+ const instanceId = ref<string | null>('inst-456')
337
+
338
+ const { isConnected } = useWorkflowWebSocket(instanceId, {
339
+ onStepChanged: (data) => {
340
+ console.log('Étape changée :', data)
341
+ // Rafraîchir l'état de l'instance
342
+ fetchInstanceAndDefinition()
343
+ },
344
+ onActionExecuted: (data) => {
345
+ console.log('Action exécutée par un autre utilisateur :', data)
346
+ },
347
+ onConflict: (data) => {
348
+ // Un autre utilisateur a agi en même temps
349
+ Notify.create({ type: 'warning', message: 'L\'état a changé. Rechargement...' })
350
+ fetchInstanceAndDefinition()
351
+ },
352
+ })
353
+ ```
354
+
355
+ La reconnexion est gérée automatiquement avec un **backoff exponentiel** (base 1s, ×2 à chaque tentative, max 30s).
356
+
357
+ ---
358
+
359
+ ## 10. useWorkflowFieldControl — contrôle des champs
360
+
361
+ Pour contrôler l'état des champs sans passer par la directive :
362
+
363
+ ```typescript
364
+ import { useWorkflowFieldControl } from '@fickou/quasar-workflow'
365
+ import { ref } from 'vue'
366
+
367
+ const entityId = ref<string | null>('inv-123')
368
+
369
+ const {
370
+ formMode, // ComputedRef<FormMode>
371
+ canEdit, // ComputedRef<boolean>
372
+ canDelete, // ComputedRef<boolean>
373
+ isLoading, // Ref<boolean>
374
+ fieldState, // (fieldName: string) => FieldState ('editable' | 'readonly' | 'disabled')
375
+ } = useWorkflowFieldControl('invoice', entityId, {
376
+ currentUserId: 'user-123',
377
+ creatorId: 'user-123',
378
+ })
379
+
380
+ // Utilisation manuelle sans directive
381
+ const amountState = computed(() => fieldState('amount'))
382
+ ```
383
+
384
+ ---
385
+
386
+ ## 11. Composants de suivi et monitoring
387
+
388
+ ### WorkflowDashboard — documents en attente d'action
389
+
390
+ Affiche la liste de tous les documents sur lesquels l'utilisateur courant doit agir.
391
+
392
+ ```vue
393
+ <WorkflowDashboard :user-id="currentUser.id" />
394
+ ```
395
+
396
+ ### WorkflowTracking — suivi créateur
397
+
398
+ Permet au créateur de suivre l'avancement de ses propres documents.
399
+
400
+ ```vue
401
+ <WorkflowTracking entity-type="invoice" :entity-id="invoiceId" />
402
+ ```
403
+
404
+ ### WorkflowAdminMonitor — monitoring global (workflow_manager)
405
+
406
+ Tableau de bord global avec filtres par statut, entity_type et période.
407
+
408
+ ```vue
409
+ <WorkflowAdminMonitor />
410
+ ```
411
+
412
+ ---
413
+
414
+ ## 12. Composants d'administration
415
+
416
+ ### WorkflowAdminBuilder — constructeur de workflow (workflow_admin)
417
+
418
+ Interface complète pour créer et modifier les définitions de workflow (étapes + transitions).
419
+
420
+ ```vue
421
+ <!-- Page d'administration -->
422
+ <WorkflowAdminBuilder entity-type="invoice" />
423
+ ```
424
+
425
+ Inclut deux onglets :
426
+ - **Étapes** : ajouter/modifier/supprimer les étapes, configurer deadline, validateurs, actions autorisées
427
+ - **Transitions** : définir les conditions de passage entre étapes via `RuleBuilderWidget`
428
+
429
+ ### WorkflowTransitionEditor — éditeur de transitions
430
+
431
+ ```vue
432
+ <WorkflowTransitionEditor :definition-id="defId" />
433
+ ```
434
+
435
+ ### RuleBuilderWidget — éditeur visuel de règles
436
+
437
+ Interface visuelle pour créer des conditions AND/OR imbriquées. Supporte les 15 opérateurs du `RuleEngineService`.
438
+
439
+ ```vue
440
+ <RuleBuilderWidget
441
+ v-model="ruleSet"
442
+ :available-fields="['amount', 'department', 'status']"
443
+ />
444
+ ```
445
+
446
+ ---
447
+
448
+ ## 13. useWorkflowDelegation — délégations
449
+
450
+ ```typescript
451
+ import { useWorkflowDelegation } from '@fickou/quasar-workflow'
452
+
453
+ const {
454
+ myDelegations, // Ref<WorkflowDelegation[]>
455
+ receivedDelegations, // Ref<WorkflowDelegation[]>
456
+ loading,
457
+ fetchMyDelegations,
458
+ fetchReceivedDelegations,
459
+ createDelegation,
460
+ revokeDelegation,
461
+ } = useWorkflowDelegation()
462
+
463
+ // Créer une délégation
464
+ await createDelegation({
465
+ delegateId: 'user-456',
466
+ scope: 'workflow',
467
+ workflowDefinitionId: 'def-789',
468
+ startDate: new Date().toISOString(),
469
+ endDate: new Date(Date.now() + 7 * 86400000).toISOString(),
470
+ type: 'delegation',
471
+ })
472
+ ```
473
+
474
+ Ou utiliser directement le composant :
475
+
476
+ ```vue
477
+ <WorkflowDelegationManager :user-id="currentUser.id" />
478
+ ```
479
+
480
+ ---
481
+
482
+ ## 14. useWorkflowStats — statistiques
483
+
484
+ Disponible uniquement pour les utilisateurs `workflow_manager` et `workflow_admin`.
485
+
486
+ ```typescript
487
+ import { useWorkflowStats } from '@fickou/quasar-workflow'
488
+
489
+ const {
490
+ delays, // Ref<DelayStats[]>
491
+ rejectionRates, // Ref<RejectionRateStats[]>
492
+ volumes, // Ref<VolumeStats[]>
493
+ loading,
494
+ fetchDelays,
495
+ fetchRejectionRates,
496
+ fetchVolumes,
497
+ } = useWorkflowStats()
498
+
499
+ await fetchDelays({ entityType: 'invoice', period: '30d' })
500
+ ```
501
+
502
+ Ou utiliser le composant intégré :
503
+
504
+ ```vue
505
+ <WorkflowStats entity-type="invoice" />
506
+ ```
507
+
508
+ ---
509
+
510
+ ## 15. Référence des composables
511
+
512
+ | Composable | Paramètres | Usage |
513
+ |---|---|---|
514
+ | `useWorkflow(entityType, entityId, options?)` | `entityType: string`, `entityId: Ref<string\|null>` | Composable principal — état + actions |
515
+ | `useWorkflowFieldControl(entityType, entityId, options?)` | idem + `currentUserId`, `creatorId` | formMode, canEdit, fieldState |
516
+ | `useWorkflowWebSocket(instanceId, callbacks?)` | `instanceId: Ref<string\|null>` | Connexion WS + callbacks |
517
+ | `useWorkflowAdmin()` | — | CRUD définitions/steps/transitions |
518
+ | `useWorkflowDashboard()` | — | Liste des instances en attente |
519
+ | `useWorkflowStats()` | — | Statistiques (manager+) |
520
+ | `useWorkflowDelegation()` | — | Gestion des délégations |
521
+
522
+ ---
523
+
524
+ ## 16. Tableau formMode / canDelete
525
+
526
+ | Contexte | `formMode` | `canEdit` | `canDelete` |
527
+ |---|---|---|---|
528
+ | `entity_id = null` | `create` | `true` | `false` |
529
+ | Pas d'instance active | `view` | `false` | `true` si `ever_started = false` |
530
+ | Instance `in_progress` | `edit` | `true` (champs editable_fields) | `false` |
531
+ | Instance `suspended` | `suspended` | `true` (champs editable_fields) | `false` |
532
+ | `correction_pending` (créateur) | `correction` | `true` | `false` |
533
+ | `completed / cancelled / rejected` | `locked` | `false` | `false` |
534
+
535
+ > **Règle absolue** : dès que `ever_started = true`, `canDelete = false` de façon **permanente**, même si l'instance est terminée. Toujours vérifier côté backend avant toute suppression.
@@ -0,0 +1,108 @@
1
+ import { Ref } from 'vue';
2
+ import { WorkflowInstanceDTO, WorkflowAction, ActionPayload, WorkflowDefinitionDTO } from '../types';
3
+ interface UseWorkflowOptions {
4
+ apiBase?: string;
5
+ wsUrl?: string;
6
+ }
7
+ export declare function useWorkflow(entityType: string, entityId: Ref<string | null>, options?: UseWorkflowOptions): {
8
+ instance: Ref<{
9
+ id: string;
10
+ entity_type: string;
11
+ entity_id: string;
12
+ status: import("../types").WorkflowStatus;
13
+ ever_started: boolean;
14
+ snapshot_id: string;
15
+ steps: {
16
+ id: string;
17
+ instance_id: string;
18
+ step_id: string;
19
+ status: "pending" | "active" | "completed" | "skipped" | "rejected";
20
+ validation_count: number;
21
+ version: number;
22
+ }[];
23
+ snapshot?: {
24
+ snapshot_data: {
25
+ id: string;
26
+ entity_type: string;
27
+ auto_start: boolean;
28
+ steps: {
29
+ id: string;
30
+ order: number;
31
+ step_type: import("../types").StepType;
32
+ validation_threshold: number;
33
+ name: string;
34
+ description?: string | undefined;
35
+ editable_fields?: string[] | undefined;
36
+ }[];
37
+ };
38
+ } | undefined;
39
+ } | null, WorkflowInstanceDTO | {
40
+ id: string;
41
+ entity_type: string;
42
+ entity_id: string;
43
+ status: import("../types").WorkflowStatus;
44
+ ever_started: boolean;
45
+ snapshot_id: string;
46
+ steps: {
47
+ id: string;
48
+ instance_id: string;
49
+ step_id: string;
50
+ status: "pending" | "active" | "completed" | "skipped" | "rejected";
51
+ validation_count: number;
52
+ version: number;
53
+ }[];
54
+ snapshot?: {
55
+ snapshot_data: {
56
+ id: string;
57
+ entity_type: string;
58
+ auto_start: boolean;
59
+ steps: {
60
+ id: string;
61
+ order: number;
62
+ step_type: import("../types").StepType;
63
+ validation_threshold: number;
64
+ name: string;
65
+ description?: string | undefined;
66
+ editable_fields?: string[] | undefined;
67
+ }[];
68
+ };
69
+ } | undefined;
70
+ } | null>;
71
+ definition: Ref<{
72
+ id: string;
73
+ entity_type: string;
74
+ auto_start: boolean;
75
+ steps: {
76
+ id: string;
77
+ order: number;
78
+ step_type: import("../types").StepType;
79
+ validation_threshold: number;
80
+ name: string;
81
+ description?: string | undefined;
82
+ editable_fields?: string[] | undefined;
83
+ }[];
84
+ } | null, WorkflowDefinitionDTO | {
85
+ id: string;
86
+ entity_type: string;
87
+ auto_start: boolean;
88
+ steps: {
89
+ id: string;
90
+ order: number;
91
+ step_type: import("../types").StepType;
92
+ validation_threshold: number;
93
+ name: string;
94
+ description?: string | undefined;
95
+ editable_fields?: string[] | undefined;
96
+ }[];
97
+ } | null>;
98
+ loading: Ref<boolean, boolean>;
99
+ error: Ref<string | null, string | null>;
100
+ hookRejectionReason: Ref<string | null, string | null>;
101
+ isWsConnected: Ref<boolean, boolean>;
102
+ fetchInstance: () => Promise<void>;
103
+ executeAction: (action: WorkflowAction, payload?: Partial<ActionPayload>) => Promise<void>;
104
+ submitWorkflow: () => Promise<void>;
105
+ resubmit: () => Promise<void>;
106
+ fetchHistory: () => Promise<any>;
107
+ };
108
+ export {};