Skip to content

Historique visible et restauration

FormBuilder enregistre chaque mutation du schéma dans un historique isolé par builder-id. Le panneau Historique transforme cet undo/redo interne en une timeline exploitable par l’utilisateur.

Le schéma courant, les étapes, les colonnes et les champs restent sérialisables. L’historique est une donnée runtime en mémoire et n’est pas ajouté au JSON exporté.

Activer et contrôler le panneau

vue
<script setup lang="ts">
const historyOpen = ref(false)
const historyDepth = ref(50)
</script>

<template>
  <FormBuilder
    builder-id="customer-form"
    v-model:history-open="historyOpen"
    v-model:history-depth="historyDepth"
  />
</template>

Props associées :

PropDéfautRôle
history-openfalseContrôle l’ouverture du panneau.
history-depth50Nombre maximal d’états conservés, borné entre 2 et 500.
history-shortcutstrueActive les raccourcis clavier undo/redo.

La profondeur est appliquée immédiatement. Réduire la valeur supprime les états les plus anciens tout en conservant l’état courant.

Timeline et libellés métier

Chaque entrée contient :

  • un identifiant stable ;
  • un numéro de séquence ;
  • un horodatage ;
  • une action métier typée ;
  • un contexte sérialisable ;
  • une copie indépendante du schéma ;
  • éventuellement un libellé personnalisé et une clé de fusion.

La timeline affiche par exemple :

  • « Champ ajouté : email » ;
  • « Colonne déplacée : coordonnées » ;
  • « Étape dupliquée : Validation » ;
  • « Schéma importé » ;
  • « État #12 restauré ».

Les libellés sont résolus au moment de l’affichage avec la locale active. L’historique ne stocke donc pas une traduction figée.

Raccourcis clavier

Lorsque history-shortcuts vaut true :

RaccourciAction
Ctrl+Z ou Cmd+ZAnnuler.
Ctrl+Shift+Z ou Cmd+Shift+ZRétablir.
Ctrl+YRétablir.

Le gestionnaire ignore les événements provenant d’un input, textarea, select, d’un éditeur contenteditable ou d’un élément ayant role="textbox". Un raccourci saisi dans un champ continue donc à modifier le texte du champ plutôt que le schéma du builder.

Avec plusieurs builders sur la même page, le dernier builder activé par un clic ou un focus devient propriétaire des raccourcis. Cette règle évite qu’un Ctrl+Z modifie plusieurs instances.

Annuler, rétablir et créer une branche

L’undo déplace le pointeur vers l’état précédent. Le redo le déplace vers l’état suivant.

Lorsqu’une modification est effectuée après un undo, les anciens états futurs sont supprimés. Une nouvelle branche d’historique commence à partir de l’état courant, comme dans un éditeur classique.

Les modifications rapides d’une même propriété utilisent une mergeKey et sont fusionnées pendant une courte fenêtre. Par exemple, saisir plusieurs caractères dans le libellé d’un champ ne crée pas une entrée par frappe.

Restaurer explicitement un état

Le bouton Restaurer cet état demande une confirmation. La restauration ne déplace pas silencieusement le pointeur vers une ancienne entrée : elle crée une nouvelle entrée history-restore à la fin de la timeline.

Cette conception garantit que la restauration elle-même peut être annulée.

API publique

vue
<script setup lang="ts">
import type {
  FormBuilderPublicApi,
  QFormBuilderHistoryChangeEvent,
  QFormBuilderHistoryNavigationEvent,
} from '@vevedh/qform-builder-layer/types'

const builder = ref<FormBuilderPublicApi | null>(null)

function restoreFirstState() {
  const history = builder.value?.getHistory()
  const first = history?.entries[0]
  if (first) builder.value?.restoreHistoryEntry(first.id)
}

function handleHistoryChange(event: QFormBuilderHistoryChangeEvent) {
  console.log(event.builderId, event.snapshot.pointer)
}

function handleUndo(event: QFormBuilderHistoryNavigationEvent) {
  console.log('État actif', event.entry.sequence)
}
</script>

<template>
  <FormBuilder
    ref="builder"
    builder-id="history-api-demo"
    @history-change="handleHistoryChange"
    @history-undo="handleUndo"
  />

  <QBtn label="Restaurer le premier état" @click="restoreFirstState" />
</template>

Méthodes exposées :

ts
getHistory(): QFormBuilderHistorySnapshot
undo(): QFormBuilderHistoryEntry | null
redo(): QFormBuilderHistoryEntry | null
restoreHistoryEntry(entryId: string): QFormBuilderHistoryEntry | null
clearHistory(): void
setHistoryDepth(depth: number): number
openHistory(): void
closeHistory(): void

Événements :

  • history-change après toute modification du pointeur, de la profondeur ou des entrées ;
  • history-undo après un undo réussi ;
  • history-redo après un redo réussi ;
  • history-restore après une restauration explicite.

Helpers publics

Le sous-chemin history expose le moteur pur, utile pour des tests ou une intégration avancée :

ts
import {
  appendQFormBuilderHistory,
  createQFormBuilderHistoryState,
  formatQFormBuilderHistoryLabel,
  normalizeQFormBuilderHistoryDepth,
  restoreQFormBuilderHistory,
} from '@vevedh/qform-builder-layer/history'

Persistance et limites

L’historique est volontairement conservé en mémoire :

  • il n’est pas écrit dans localStorage par l’autosave ;
  • il n’est pas exporté avec le schéma ;
  • il n’est pas envoyé automatiquement au service NFZ forms ;
  • il disparaît lors du démontage définitif de l’instance.

Pour un audit durable, persistez des versions métier côté serveur dans un service Feathers/NFZ distinct. Ne confondez pas l’historique ergonomique du builder avec un journal d’audit réglementaire.

Bonnes pratiques

  • Utiliser un builder-id stable.
  • Conserver une profondeur de 30 à 100 pour la majorité des formulaires.
  • Désactiver history-shortcuts lorsque l’application hôte possède déjà un gestionnaire global de raccourcis.
  • Confirmer explicitement toute restauration depuis la timeline.
  • Ne jamais utiliser l’historique client comme mécanisme d’autorisation, de sauvegarde ou de preuve d’audit.

QForm Builder — layer Nuxt 4, Quasar et FormKit pour formulaires dynamiques.