Canvas d'automatisation (AutomationCanvas)
Canvas d'automatisation
Le composant AutomationCanvas du framework (@framework/ui) permet d'afficher un flux d'automatisation sous forme de canvas interactif. Il vient du constructeur de workflows du CRM.
Import
Importez le composant depuis @framework/ui/AutomationCanvas (et non depuis la racine du package) afin que 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";
Le composant est contrôlé : votre application possède le flux et sa mise en page. Vous fournissez les nodes et les edges, et vous réagissez aux événements émis. Le canvas ne modifie jamais le flux lui-même.
Prérequis
@vue-flow/coreet@vue-flow/background, dépendances de@framework/ui- Vue 3 avec TypeScript recommandé pour bénéficier des types exportés
Utilisation de base
<template>
<AutomationCanvas
ref="canvasRef"
:nodes="nodes"
:edges="edges"
:start-options="startOptions"
:block-options="blockOptions"
:selected-id="selectedId"
:readonly="readonly"
@select="onSelect"
@pick-start="onPickStart"
@add-node="onAddNode"
@run-branch="onRunBranch"
@move="onMove"
>
<template #toolbar="{ selectedId }">
<Button
icon="lucide-undo-2"
variant="ghost"
aria-label="Annuler"
@click="undo"
/>
<Button
v-if="selectedId"
icon="lucide-trash-2"
variant="ghost"
class="text-ink-red-5"
aria-label="Supprimer l'étape"
@click="remove(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,
AutomationCanvasRunBranchPayload,
} from "@framework/ui/AutomationCanvas";
const canvasRef = ref<InstanceType<typeof AutomationCanvas>>();
const nodes = ref<AutomationCanvasNode[]>([
{
id: "start",
position: { x: 0, y: 0 },
data: {
kicker: "Déclencheur",
label: "L'enregistrement est créé",
detail: "Sur le DocType Prospect",
icon: "lucide-play",
tone: "blue",
start: true,
},
},
]);
const edges = ref<AutomationCanvasEdge[]>([]);
const selectedId = ref<string | undefined>(undefined);
const readonly = ref(false);
const startOptions: AutomationCanvasOptionGroup[] = [
{
group: "Déclencheurs",
options: [
{
value: "created",
label: "L'enregistrement est créé",
description: "Démarrer à chaque création d'enregistrement",
icon: "lucide-play",
tone: "blue",
},
],
},
];
const blockOptions: AutomationCanvasOptionGroup[] = [
{
group: "Flux",
options: [
{
value: "wait",
label: "Attendre",
description: "Mettre en pause pendant une durée fixe",
icon: "lucide-timer",
tone: "amber",
},
],
},
{
group: "Actions",
options: [
{
value: "email",
label: "Envoyer un e-mail",
icon: "lucide-mail",
tone: "violet",
},
],
},
];
function onSelect(nodeId: string) {
selectedId.value = nodeId;
}
function onPickStart(value: string) {
// Configurer le nœud de départ avec l'option choisie
}
function onAddNode(payload: AutomationCanvasAddNodePayload) {
// Ajouter un nœud après payload.afterId (ou au départ si null)
// sur la branche payload.branch si spécifiée, avec la valeur payload.value
}
function onRunBranch(payload: AutomationCanvasRunBranchPayload) {
// Relancer la branche payload.arm du nœud payload.nodeId
}
function onMove(payload: AutomationCanvasMovePayload) {
// Persister la nouvelle position pour conserver le déplacement
const node = nodes.value.find((n) => n.id === payload.nodeId);
if (node) {
node.position = payload.position;
}
}
</script>
Propriétés (Props)
| Prop | 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 | "" | Identifiant du nœud actuellement sélectionné |
startOptions | AutomationCanvasOptionGroup[] | [] | Options proposées pour le déclencheur de départ |
blockOptions | AutomationCanvasOptionGroup[] | [] | Options proposées pour ajouter des étapes |
readonly | boolean | false | Mode lecture seule (désactive les interactions de modification) |
Événements (Events)
| Événement | Payload | Description |
|---|---|---|
select | nodeId: string | Un nœud a été sélectionné |
pick-start | value: string | Une option de déclencheur a été choisie dans le sélecteur de départ |
add-node | AutomationCanvasAddNodePayload | Demande d'ajout d'un nœud après afterId (ou au départ si null), sur la branche branch si spécifiée |
run-branch | AutomationCanvasRunBranchPayload | Demande de (re)lancement d'une branche spécifique d'un nœud (nodeId et arm) |
move | AutomationCanvasMovePayload | Un nœud a été déplacé ; persistez la position (nodeId et position) pour la conserver |
Types des payloads
interface AutomationCanvasAddNodePayload {
afterId: string | null;
branch: string | null;
value: string;
}
interface AutomationCanvasMovePayload {
nodeId: string;
position: { x: number; y: number };
}
interface AutomationCanvasRunBranchPayload {
nodeId: string;
arm: AutomationCanvasArm;
}
interface AutomationCanvasArm {
key: string;
label: string;
}
Slot toolbar
Le slot #toolbar reçoit selectedId et permet d'ajouter des contrôles d'application (annuler, rétablir, supprimer, etc.). Ces contrôles apparaissent avant les boutons intégrés de zoom et d'ajustement de la vue.
<template #toolbar="{ selectedId }">
<Button icon="lucide-undo-2" variant="ghost" aria-label="Annuler" @click="undo" />
<Button
icon="lucide-redo-2"
variant="ghost"
aria-label="Rétablir"
:disabled="!canRedo"
@click="redo"
/>
<Button
v-if="selectedId"
icon="lucide-trash-2"
variant="ghost"
class="text-ink-red-5"
aria-label="Supprimer l'étape"
@click="remove(selectedId)"
/>
</template>
Méthodes exposées
Le composant expose une méthode accessible via la référence (ref) :
| Méthode | Retour | Description |
|---|---|---|
fitView() | Promise<void> | Recalcule la vue pour afficher l'ensemble du flux dans le conteneur |
const canvasRef = ref<InstanceType<typeof AutomationCanvas>>();
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;
}
Données du nœud (AutomationCanvasNodeData)
| Champ | Type | Description |
|---|---|---|
kicker | string | Catégorie affichée en haut du bloc (ex: « Déclencheur », « Action », « Condition ») |
label | string | Titre principal du nœud |
detail | string? | Description ou sous-titre optionnel |
icon | string | Component? | Icône (nom Lucide ou composant Vue) |
tone | AutomationCanvasTone? | Couleur d'identité du nœud (onglet, liseré et sélection) |
start | boolean? | Marque le nœud comme point de départ du flux |
empty | boolean? | État vide : affiche le sélecteur de déclencheur |
issue | AutomationCanvasIssue? | Problème à signaler (erreur ou avertissement) |
run | AutomationCanvasRun? | État d'une exécution d'essai (trial run) |
dimmed | boolean? | Atténue le nœud (par exemple quand un autre nœud est inspecté) |
branching | boolean? | Indique que le nœud est une condition avec branches |
terminal | boolean? | Marque le nœud comme terminal (affiche le bouton « + ») |
arms | AutomationCanvasArm[]? | Bras de branche vides à proposer pour ajout |
canContinue | boolean? | Propose une étape « Après les branches » quand toutes les branches sont terminées |
Tons disponibles (AutomationCanvasTone)
Les valeurs possibles pour la propriété tone sont :
blue, green, teal, amber, violet, cyan, orange, pink, red, gray, purple
Chaque ton colore l'onglet du bloc, son liseré et sa bordure de sélection.
Problème (AutomationCanvasIssue)
interface AutomationCanvasIssue {
level: "error" | "warning";
message: string;
}
level: "warning"affiche « Needs setup » (configuration requise)level: "error"affiche « Has errors » (erreurs présentes)- Le
messages'affiche en info-bulle au survol du nœud
État d'exécution (AutomationCanvasRun)
type AutomationCanvasStatus =
| "running"
| "Success"
| "Skipped"
| "Failed"
| "Waiting";
interface AutomationCanvasRun {
status: AutomationCanvasStatus;
forced?: boolean;
retryArms?: AutomationCanvasArm[];
durationMs?: number;
}
| Champ | Description |
|---|---|
status | État laissé par l'exécution d'essai : running (en cours), Success (succès), Skipped (ignoré), Failed (échec), Waiting (en attente) |
forced | L'exécution a pris cette branche indépendamment de sa condition (badge « Forcé ») |
retryArms | Bras de branche ignorés par l'exécution et pouvant être relancés |
durationMs | Durée d'exécution affichée dans le pied du nœud |
Connexion (AutomationCanvasEdge)
interface AutomationCanvasEdge {
id: string;
source: string;
target: string;
label?: string;
animated?: boolean;
style?: Record<string, string | number>;
}
Options de sélecteur (AutomationCanvasOptionGroup)
interface AutomationCanvasOptionGroup {
group: string;
options: AutomationCanvasPickerOption[];
}
interface AutomationCanvasPickerOption {
value: string;
label: string;
description?: string;
icon?: string | Component;
tone?: AutomationCanvasTone;
[key: string]: unknown;
}
États visuels des nœuds
Le canvas gère automatiquement plusieurs états visuels selon les données fournies :
- Sélecteur de départ vide : nœud de départ avec
empty: trueaffichant le sélecteur de déclencheurs - Terminal « + » : bouton d'ajout après un nœud marqué
terminal: true - Bras de branche : boutons d'ajout sur chaque branche d'un nœud
branching: true - « Après les branches » : option de continuation proposée quand
canContinue: trueet que toutes les branches ont un nœud - Problème (
issue) : badge d'erreur (rouge) ou d'avertissement (ambre) avec message au survol - Exécution (
run) : pied de carte avec statut coloré, badge « Forcé » si applicable, durée d'exécution, et boutons de relance pour les brasretryArms - Atténué (
dimmed: true) : nœud grisé, utilisé typiquement quand un autre nœud est sélectionné pour inspection
Exemple de flux avec branches
const nodes: AutomationCanvasNode[] = [
{
id: "start",
position: { x: 0, y: 0 },
data: {
kicker: "Déclencheur",
label: "Prospect créé",
icon: "lucide-play",
tone: "blue",
start: true,
},
},
{
id: "condition",
position: { x: 320, y: 0 },
data: {
kicker: "Condition",
label: "Statut qualifié",
detail: "Le statut du prospect est « Qualifié »",
icon: "lucide-git-branch",
tone: "green",
branching: true,
},
},
{
id: "email-yes",
position: { x: 640, y: -132 },
data: {
kicker: "Action",
label: "Envoyer e-mail de bienvenue",
icon: "lucide-mail",
tone: "violet",
},
},
{
id: "assign-no",
position: { x: 640, y: 132 },
data: {
kicker: "Action",
label: "Assigner au commercial",
icon: "lucide-user-plus",
tone: "violet",
},
},
];
const edges: AutomationCanvasEdge[] = [
{ id: "start->condition", source: "start", target: "condition" },
{
id: "condition->email-yes",
source: "condition",
target: "email-yes",
label: "Si oui",
},
{
id: "condition->assign-no",
source: "condition",
target: "assign-no",
label: "Sinon",
},
];
Scénarios de démonstration
Le fichier ui/src/components/AutomationCanvas/stories/AutomationCanvas.story.vue présente huit états du canvas : départ vide, flux linéaire, branche avec un bras vide, branches prêtes à rejoindre, inspection d’un nœud (nœuds atténués), erreurs et nœuds incomplets, exécution d’essai, et lecture seule. Utilisez-les comme référence visuelle.