Version de développement
Cette documentation décrit la version « next » (develop), non encore publiée. Pour la version stable, basculez sur « v5 » dans l'en-tête.
Développeurs

Canvas d'automatisation (AutomationCanvas)

Composant partagé du framework pour afficher et interagir avec des flux d'automatisation

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/core et @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)

PropTypeDéfautDescription
nodesAutomationCanvasNode[]requisListe des nœuds du flux
edgesAutomationCanvasEdge[]requisListe des connexions entre les nœuds
selectedIdstring""Identifiant du nœud actuellement sélectionné
startOptionsAutomationCanvasOptionGroup[][]Options proposées pour le déclencheur de départ
blockOptionsAutomationCanvasOptionGroup[][]Options proposées pour ajouter des étapes
readonlybooleanfalseMode lecture seule (désactive les interactions de modification)

Événements (Events)

ÉvénementPayloadDescription
selectnodeId: stringUn nœud a été sélectionné
pick-startvalue: stringUne option de déclencheur a été choisie dans le sélecteur de départ
add-nodeAutomationCanvasAddNodePayloadDemande d'ajout d'un nœud après afterId (ou au départ si null), sur la branche branch si spécifiée
run-branchAutomationCanvasRunBranchPayloadDemande de (re)lancement d'une branche spécifique d'un nœud (nodeId et arm)
moveAutomationCanvasMovePayloadUn 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éthodeRetourDescription
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)

ChampTypeDescription
kickerstringCatégorie affichée en haut du bloc (ex: « Déclencheur », « Action », « Condition »)
labelstringTitre principal du nœud
detailstring?Description ou sous-titre optionnel
iconstring | Component?Icône (nom Lucide ou composant Vue)
toneAutomationCanvasTone?Couleur d'identité du nœud (onglet, liseré et sélection)
startboolean?Marque le nœud comme point de départ du flux
emptyboolean?État vide : affiche le sélecteur de déclencheur
issueAutomationCanvasIssue?Problème à signaler (erreur ou avertissement)
runAutomationCanvasRun?État d'une exécution d'essai (trial run)
dimmedboolean?Atténue le nœud (par exemple quand un autre nœud est inspecté)
branchingboolean?Indique que le nœud est une condition avec branches
terminalboolean?Marque le nœud comme terminal (affiche le bouton « + »)
armsAutomationCanvasArm[]?Bras de branche vides à proposer pour ajout
canContinueboolean?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 message s'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;
}
ChampDescription
statusÉtat laissé par l'exécution d'essai : running (en cours), Success (succès), Skipped (ignoré), Failed (échec), Waiting (en attente)
forcedL'exécution a pris cette branche indépendamment de sa condition (badge « Forcé »)
retryArmsBras de branche ignorés par l'exécution et pouvant être relancés
durationMsDuré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: true affichant 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: true et 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 bras retryArms
  • 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.