Canvas d'automatisation
Le composant AutomationCanvas permet de dessiner un flux d'automatisation dans n'importe quelle application. Il vient du constructeur de workflows du CRM et fait partie du paquet @framework/ui.
Importation
Importez le composant depuis @framework/ui/AutomationCanvas. Il n'est pas exposé sur le barrel racine : les applications qui ne l'utilisent pas ne chargent pas Vue Flow.
import { AutomationCanvas } from '@framework/ui/AutomationCanvas'
import type {
AutomationCanvasNode,
AutomationCanvasEdge,
AutomationCanvasNodeData,
AutomationCanvasOptionGroup,
} from '@framework/ui/AutomationCanvas'
Principe de fonctionnement
Le composant est contrôlé. Votre application possède le flux et sa disposition :
- Vous fournissez les
nodeset lesedges - Vous réagissez aux événements pour modifier le flux
- Le canvas ne modifie jamais le flux lui-même
Les positions des nœuds doivent être persistées par votre application lorsque l'événement move est émis.
Exemple d'utilisation
<template>
<AutomationCanvas
:nodes="nodes"
:edges="edges"
:selected-id="selectedId"
:start-options="startOptions"
:block-options="blockOptions"
:readonly="false"
@select="onSelect"
@pick-start="onPickStart"
@add-node="onAddNode"
@move="onMove"
>
<template #toolbar="{ selectedId }">
<Button
v-if="selectedId"
icon="lucide-trash-2"
variant="ghost"
@click="deleteNode(selectedId)"
/>
</template>
</AutomationCanvas>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { AutomationCanvas } from '@framework/ui/AutomationCanvas'
import type {
AutomationCanvasNode,
AutomationCanvasEdge,
AutomationCanvasOptionGroup,
AutomationCanvasAddNodePayload,
AutomationCanvasMovePayload,
} from '@framework/ui/AutomationCanvas'
const nodes = ref<AutomationCanvasNode[]>([
{
id: 'start',
position: { x: 0, y: 0 },
data: {
kicker: 'Déclencheur',
label: 'Nouveau document',
detail: 'Quand un document est créé',
icon: 'lucide-play',
tone: 'blue',
start: true,
},
},
])
const edges = ref<AutomationCanvasEdge[]>([])
const selectedId = ref<string>()
const startOptions: AutomationCanvasOptionGroup[] = [
{
group: 'Documents',
options: [
{
value: 'created',
label: 'Document créé',
description: "Se déclenche à la création d'un document",
icon: 'lucide-play',
tone: 'blue',
},
],
},
]
const blockOptions: AutomationCanvasOptionGroup[] = [
{
group: 'Actions',
options: [
{
value: 'email',
label: 'Envoyer un email',
icon: 'lucide-mail',
tone: 'violet',
},
],
},
]
function onSelect(nodeId: string) {
selectedId.value = nodeId
}
function onPickStart(value: string) {
// Mettre à jour le nœud de départ avec la valeur choisie
}
function onAddNode(payload: AutomationCanvasAddNodePayload) {
// Ajouter un nouveau nœud après `payload.afterId` (ou au début si null)
// sur la branche `payload.branch` (ou null) avec la valeur `payload.value`
}
function onMove(payload: AutomationCanvasMovePayload) {
// Persister la nouvelle position du nœud
const node = nodes.value.find(n => n.id === payload.nodeId)
if (node) {
node.position = payload.position
}
}
function deleteNode(nodeId: string) {
nodes.value = nodes.value.filter(n => n.id !== nodeId)
edges.value = edges.value.filter(
e => e.source !== nodeId && e.target !== nodeId
)
selectedId.value = undefined
}
</script>
Propriétés
| Propriété | Type | Défaut | Description |
|---|---|---|---|
nodes | AutomationCanvasNode[] | requis | Liste des nœuds du flux |
edges | AutomationCanvasEdge[] | requis | Liste des connexions entre les nœuds |
selectedId | string | "" | ID du nœud actuellement sélectionné |
startOptions | AutomationCanvasOptionGroup[] | [] | Options pour le sélecteur de déclencheur initial |
blockOptions | AutomationCanvasOptionGroup[] | [] | Options pour l'ajout de blocs dans le flux |
readonly | boolean | false | Désactive les interactions de modification |
Événements
| Événement | Payload | Description |
|---|---|---|
select | nodeId: string | Émis quand un nœud est sélectionné |
pick-start | value: string | Émis quand un déclencheur initial est choisi dans le sélecteur de départ |
add-node | { afterId: string | null, branch: string | null, value: string } | Émis pour ajouter un bloc. afterId indique le nœud après lequel insérer (null pour le début), branch indique la branche concernée (null pour le flux principal), value est la valeur de l'option choisie |
run-branch | { nodeId: string, arm: AutomationCanvasArm } | Émis pour lancer un essai sur une branche spécifique d'un nœud de condition |
move | { nodeId: string, position: { x: number, y: number } } | Émis quand un nœud est déplacé. Utilisez cet événement pour persister la position |
Slot toolbar
Le slot #toolbar reçoit selectedId et permet d'ajouter des contrôles personnalisés (annuler, refaire, supprimer, etc.) qui s'affichent avant les boutons de zoom et d'ajustement intégrés.
<template #toolbar="{ selectedId }">
<Button
v-if="selectedId"
icon="lucide-trash-2"
variant="ghost"
aria-label="Supprimer"
@click="remove(selectedId)"
/>
</template>
Méthodes exposées
Le composant expose la méthode fitView() via une ref, qui retourne une Promise et permet de recadrer la vue sur l'ensemble du flux depuis l'extérieur :
const canvasRef = ref()
async function resetView() {
await canvasRef.value?.fitView()
}
Structure des données
Nœud (AutomationCanvasNode)
interface AutomationCanvasNode {
id: string
position: { x: number; y: number }
data: AutomationCanvasNodeData
}
Connexion (AutomationCanvasEdge)
interface AutomationCanvasEdge {
id: string
source: string // ID du nœud source
target: string // ID du nœud cible
label?: string // Étiquette sur la connexion (ex: "Si oui")
animated?: boolean // Animation de la connexion
style?: Record<string, string | number> // Style CSS personnalisé
}
Données du nœud (AutomationCanvasNodeData)
| Champ | Type | Description |
|---|---|---|
kicker | string | Catégorie du nœud (ex: "Action", "Condition", "Déclencheur") |
label | string | Titre affiché sur le nœud |
detail | string | Sous-titre ou description (optionnel) |
icon | string | Component | Icône affichée (nom Lucide ou composant Vue) |
tone | AutomationCanvasTone | Couleur d'identité du nœud (voir ci-dessous) |
start | boolean | Indique le nœud de départ du flux |
empty | boolean | Nœud de départ vide affichant un sélecteur de déclencheur |
issue | AutomationCanvasIssue | Problème sur le nœud (erreur ou avertissement) |
run | AutomationCanvasRun | État d'un essai (trial run) sur ce nœud |
dimmed | boolean | Estompe le nœud (utile quand un autre est sélectionné) |
branching | boolean | Indique un nœud de branchement (condition) |
terminal | boolean | Nœud final affichant un bouton "+" pour continuer |
arms | AutomationCanvasArm[] | Branches vides attendant un contenu |
canContinue | boolean | Propose une étape "Après les branches" quand toutes les branches sont remplies |
Tons de couleur (AutomationCanvasTone)
Les valeurs possibles sont : blue, green, teal, amber, violet, cyan, orange, pink, red, gray, purple.
La couleur s'applique à l'onglet du nœud, au filet et à la sélection.
États d'essai (AutomationCanvasRun)
Lors d'un essai (trial run), un nœud peut afficher son état :
interface AutomationCanvasRun {
status: 'running' | 'Success' | 'Skipped' | 'Failed' | 'Waiting'
forced?: boolean // L'essai a pris cette branche malgré la condition
retryArms?: AutomationCanvasArm[] // Branches sautées pouvant être relancées
durationMs?: number // Durée d'exécution affichée dans le pied du nœud
}
Problèmes (AutomationCanvasIssue)
interface AutomationCanvasIssue {
level: 'error' | 'warning'
message: string // Affiché dans une info-bulle au survol
}
Un avertissement affiche « Nécessite une configuration », une erreur affiche « Contient des erreurs ».
Options de sélecteur
interface AutomationCanvasOptionGroup {
group: string
options: AutomationCanvasPickerOption[]
}
interface AutomationCanvasPickerOption {
value: string
label: string
description?: string
icon?: string | Component
tone?: AutomationCanvasTone
[key: string]: unknown // Propriétés additionnelles personnalisées
}
Dépendances
L'ajout de ce composant introduit les dépendances suivantes dans ui/package.json :
@vue-flow/core^1.48.2@vue-flow/background^1.3.2
Ces dépendances ne sont chargées que si vous importez le composant via @framework/ui/AutomationCanvas.