Développeurs

Canvas d'automatisation

Utiliser le composant AutomationCanvas pour dessiner des flux d'automatisation dans les applications Dokos

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 nodes et les edges
  • 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éTypeDéfautDescription
nodesAutomationCanvasNode[]requisListe des nœuds du flux
edgesAutomationCanvasEdge[]requisListe des connexions entre les nœuds
selectedIdstring""ID du nœud actuellement sélectionné
startOptionsAutomationCanvasOptionGroup[][]Options pour le sélecteur de déclencheur initial
blockOptionsAutomationCanvasOptionGroup[][]Options pour l'ajout de blocs dans le flux
readonlybooleanfalseDésactive les interactions de modification

Événements

ÉvénementPayloadDescription
selectnodeId: stringÉmis quand un nœud est sélectionné
pick-startvalue: 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)

ChampTypeDescription
kickerstringCatégorie du nœud (ex: "Action", "Condition", "Déclencheur")
labelstringTitre affiché sur le nœud
detailstringSous-titre ou description (optionnel)
iconstring | ComponentIcône affichée (nom Lucide ou composant Vue)
toneAutomationCanvasToneCouleur d'identité du nœud (voir ci-dessous)
startbooleanIndique le nœud de départ du flux
emptybooleanNœud de départ vide affichant un sélecteur de déclencheur
issueAutomationCanvasIssueProblème sur le nœud (erreur ou avertissement)
runAutomationCanvasRunÉtat d'un essai (trial run) sur ce nœud
dimmedbooleanEstompe le nœud (utile quand un autre est sélectionné)
branchingbooleanIndique un nœud de branchement (condition)
terminalbooleanNœud final affichant un bouton "+" pour continuer
armsAutomationCanvasArm[]Branches vides attendant un contenu
canContinuebooleanPropose 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.