Skip to content

Opérations longues et journaux ​

Le problème ​

Un déploiement, un import, une synchronisation, un envoi en masse : une opération qui dure, qui échoue parfois et qu'on relance. L'écran qui la suit répond toujours aux mêmes questions :

  • où en est-elle ? En file d'attente, en cours, terminée, en échec ;
  • qu'a-t-elle fait ? Le journal ligne à ligne, les essais successifs ;
  • qu'a répondu le serveur ? Une charge utile, une erreur détaillée ;
  • sur quel service ? Le logo du fournisseur concerné.

Quatre composants y répondent, et se composent :

ComposantRépond à
JobProgressle statut, les étapes, la progression, les essais, la durée, l'erreur, la relance
LogStreamle journal : niveaux, heure, groupes par essai, filtres, recherche, copie, suivi de la fin
JsonViewune réponse ou une configuration JSON, en lecture seule, repliable et copiable
BrandIconle logo d'un service tiers, sans dépendance à un paquet d'icônes

Comment ils s'assemblent ​

JobProgress reçoit le journal par sa prop logs : il le place sous le statut, sans en connaître la forme. Une ligne de LogStream accepte un ReactNode : un JsonView replié y tient quand le message est une charge utile.

tsx
<JobProgress
  title={<><BrandIcon icon={siVercel} decorative /> Déploiement</>}
  status={job.status}
  steps={job.steps}
  currentStep={job.currentStep}
  attempts={{ current: job.attempt, max: 3 }}
  startedAt={job.startedAt}
  error={job.error}
  onRetry={() => relancer(job.id)}
  logs={<LogStream lines={job.lines} streaming={job.status === "running"} height={320} />}
/>

Le temps réel ​

Ces composants ne s'abonnent à rien. Les données arrivent par le cache de requêtes de l'application, que createRealtimeBinding met à jour à chaque événement du serveur. Voir Module API. Le composant se redessine comme pour n'importe quelle donnée, et LogStream suit la fin du journal tant que la personne n'a pas remonté pour lire.

Les choix ​

  • LogStream limite ce qu'il garde (maxLines) : un journal qui défile pendant une heure ne doit pas faire grossir la page sans fin.
  • JsonView ne rend pas une branche repliée : un document de plusieurs milliers de nœuds s'affiche sans attendre. Un texte invalide s'affiche tel quel sous une alerte, car une réponse tronquée reste utile à lire.
  • BrandIcon ne livre aucun logo : le projet importe l'objet de simple-icons qu'il veut et reste maître de sa version. Une marque quasi noire ou quasi blanche prend la couleur du texte là où elle serait illisible.
  • Les textes viennent de la locale : statuts, niveaux (INFO, ERREUR), « Suivre la fin », « {count} clés ». Voir Langues, libellés et réglages.

Chacun expose les props de ses sous-composants (statusBadgeProps, progressProps, copyButtonProps, alertProps…), transmises telles quelles.

Publié sous licence MIT.