Navigation dans les fiches

La plupart des modules complémentaires basés sur des fiches sont créés à l'aide de plusieurs fiches représentant différentes "pages" de l'interface du module complémentaire. Pour une expérience utilisateur efficace, vous devez utiliser une navigation simple et naturelle entre les fiches de votre module complémentaire.

À l'origine dans les modules complémentaires Gmail, les transitions entre les différentes cartes de l'interface utilisateur étaient gérées en envoyant et en affichant des cartes vers et depuis une seule pile de cartes, avec la première carte affichée par Gmail.

Navigation dans la fiche de la page d'accueil

Les modules complémentaires Google Workspace présentent les pages d'accueil et les fiches non contextuelles. Pour accueillir des fiches contextuelles et non contextuelles, les modules complémentaires Google Workspace disposent d'une pile de cartes interne pour chacun. Lorsqu'un module complémentaire est ouvert sur un hôte, le homepageTrigger correspondant se déclenche pour créer la première fiche de la page d'accueil dans la pile (la fiche bleu foncé "homepage" dans le schéma ci-dessous). Si aucun élément homepageTrigger n'est défini, une carte par défaut est créée, affichée et transférée vers la pile non contextuelle. Cette première fiche est une fiche racine.

Votre module complémentaire peut créer des cartes non contextuelles supplémentaires et les insérer dans la pile (les "cartes envoyées" en bleu dans le diagramme) à mesure que l'utilisateur parcourt le module. L'interface utilisateur du module complémentaire affiche la première carte de la pile. Le fait d'ajouter de nouvelles cartes dans la pile modifie donc l'affichage, et lorsque vous retirez des cartes de la pile, l'affichage revient aux cartes précédentes.

Si votre module complémentaire dispose d'un déclencheur contextuel défini, le déclencheur est exécuté lorsque l'utilisateur entre dans ce contexte. La fonction de déclencheur crée la carte contextuelle, mais l'affichage de l'UI est mis à jour en fonction du DisplayStyle de la nouvelle carte:

  • Si DisplayStyle est REPLACE (valeur par défaut), la carte contextuelle (la carte "contextuelle" orange foncé dans le diagramme) remplace la carte actuellement affichée. Cela démarre effectivement une nouvelle pile de cartes contextuelles au-dessus de la pile de cartes non contextuelles. Cette carte contextuelle est la carte racine de la pile contextuelle.
  • Si DisplayStyle est défini sur PEEK, l'interface utilisateur crée un en-tête en aperçu qui apparaît en bas de la barre latérale du module complémentaire et qui se superpose à la fiche actuelle. L'en-tête de l'aperçu affiche le titre de la nouvelle fiche et fournit des commandes à l'aide des boutons de l'utilisateur qui permettent de décider s'il souhaite la consulter ou non. S'il clique sur le bouton Afficher, la fiche remplace la carte actuelle (comme décrit ci-dessus par REPLACE).

Vous pouvez créer des fiches contextuelles supplémentaires et les insérer dans la pile (les "cartes envoyées" en jaune dans le schéma). La mise à jour de la pile de cartes modifie l'interface utilisateur du module complémentaire pour afficher la fiche supérieure. Si l'utilisateur quitte un contexte, les fiches contextuelles de la pile sont supprimées et l'affichage est mis à jour vers la page ou la carte non contextuelle de niveau supérieur.

Si l'utilisateur entre dans un contexte pour lequel votre module complémentaire ne définit pas de déclencheur contextuel, aucune fiche n'est créée et la carte actuelle reste affichée.

Les actions Navigation décrites ci-dessous n'agissent que sur les fiches du même contexte. Par exemple, popToRoot() à partir d'une fiche contextuelle n'affiche que toutes les autres fiches contextuelles et n'affecte pas les fiches de la page d'accueil.

En revanche, le bouton est toujours disponible pour permettre à l'utilisateur de naviguer entre vos fiches contextuelles et vos fiches non contextuelles.

Vous pouvez créer des transitions entre les cartes en ajoutant ou en supprimant des cartes dans les piles de cartes. La classe Navigation fournit des fonctions permettant de transférer et d'afficher des fiches depuis les piles. Pour créer une navigation efficace dans les fiches, vous devez configurer vos widgets pour utiliser des actions de navigation. Vous pouvez insérer ou afficher plusieurs fiches simultanément, mais vous ne pouvez pas supprimer la fiche de la page d'accueil initiale qui est ajoutée pour la première fois à la pile au démarrage du module complémentaire.

Pour accéder à une nouvelle fiche en réponse à une interaction utilisateur avec un widget, procédez comme suit:

  1. Créez un objet Action et associez-le à une fonction de rappel que vous définissez.
  2. Appelez la fonction de gestionnaire de widgets appropriée pour définir la Action sur ce widget.
  3. Implémentez la fonction de rappel qui effectue la navigation. Un objet d'événement d'action est attribué à cette fonction en tant qu'argument et doit effectuer les opérations suivantes :
    1. Créez un objet Navigation pour définir la modification de la fiche. Un seul objet Navigation peut contenir plusieurs étapes de navigation, qui sont effectuées dans l'ordre dans lequel elles ont été ajoutées à l'objet.
    2. Créez un objet ActionResponse à l'aide de la classe ActionResponseBuilder et de l'objet Navigation.
    3. Renvoyez le ActionResponse compilé.

Lorsque vous créez des commandes de navigation, vous utilisez les fonctions d'objet Navigation suivantes:

Fonction Description
Navigation.pushCard(Card) Envoie une carte dans la pile actuelle. Pour ce faire, vous devez d'abord créer la carte.
Navigation.popCard() Supprime une fiche du haut de la pile. Cela équivaut à cliquer sur la flèche de retour dans la ligne d'en-tête du module complémentaire. Cela ne supprime pas les cartes racine.
Navigation.popToRoot() Supprime toutes les cartes de la pile, à l'exception de la carte racine. En bref, la pile de cartes est réinitialisée.
Navigation.popToNamedCard(String) Faire sortir les cartes de la pile jusqu'à ce qu'elle atteigne une carte portant le nom donné ou la carte racine de la pile. Vous pouvez attribuer des noms aux fiches à l'aide de la fonction CardBuilder.setName(String).
Navigation.updateCard(Card) Remplacement de la carte actuelle sur place par l'actualisation de son affichage dans l'interface utilisateur.

Si une interaction ou un événement utilisateur doit entraîner le réaffichage des fiches dans le même contexte, utilisez les méthodes Navigation.pushCard(), Navigation.popCard() et Navigation.updateCard() pour remplacer les fiches existantes. Si une interaction ou un événement utilisateur doit entraîner un nouvel affichage des fiches dans un autre contexte, utilisez ActionResponseBuilder.setStateChanged() pour forcer la réexécution de votre module complémentaire dans ces contextes.

Voici des exemples de navigation:

  • Si une interaction ou un événement modifie l'état de la fiche actuelle (par exemple, en ajoutant une tâche à une liste de tâches), utilisez updateCard().
  • Si une interaction ou un événement fournit des détails supplémentaires ou invite l'utilisateur à effectuer une action supplémentaire (par exemple, cliquer sur le titre d'un élément pour afficher plus de détails, ou appuyer sur un bouton pour créer un événement d'agenda), utilisez pushCard() pour afficher la nouvelle page tout en permettant à l'utilisateur de la quitter à l'aide du bouton "Retour".
  • Si une interaction ou un événement met à jour l'état d'une fiche précédente (par exemple, en modifiant le titre d'un élément à partir de la vue détaillée), utilisez des éléments tels que popCard(), popCard(), pushCard(previous) et pushCard(current) pour mettre à jour la fiche précédente et la fiche actuelle.

Actualisation des fiches...

Les modules complémentaires Google Workspace permettent aux utilisateurs d'actualiser votre carte en exécutant à nouveau la fonction de déclencheur Apps Script enregistrée dans votre fichier manifeste. Les utilisateurs déclenchent cette actualisation via un élément de menu complémentaire:

Barre latérale du module complémentaire Google Workspace

Cette action est automatiquement ajoutée aux cartes générées par les fonctions de déclencheur homepageTrigger ou contextualTrigger, comme indiqué dans le fichier manifeste de votre module complémentaire (les "racines" des piles de cartes contextuelles et non contextuelles).

Renvoi de plusieurs cartes

Exemple de fiche complémentaire

Les fonctions de page d'accueil ou de déclencheur contextuel permettent de créer et de renvoyer un seul objet Card ou un tableau d'objets Card que l'interface utilisateur de l'application affiche.

S'il n'y a qu'une seule carte, elle est ajoutée à la pile non contextuelle ou contextuelle en tant que carte racine et dans l'UI de l'application hôte.

Si le tableau renvoyé comprend plusieurs objets Card créés, l'application hôte affiche à la place une nouvelle fiche, qui contient une liste de l'en-tête de chaque carte. Lorsque l'utilisateur clique sur l'un de ces en-têtes, l'UI affiche la carte correspondante.

Lorsque l'utilisateur sélectionne une carte dans la liste, elle est transférée vers la pile actuelle et l'application hôte l'affiche. Le bouton renvoie l'utilisateur à la liste d'en-têtes de la fiche.

Cette disposition de cartes "plate" peut fonctionner correctement si votre module complémentaire ne nécessite aucune transition entre les cartes que vous créez. Dans la plupart des cas, il est toutefois préférable de définir directement les transitions de cartes, et de faire en sorte que votre page d'accueil et les fonctions de déclenchement contextuel renvoient un seul objet carte.

Exemple

Voici un exemple illustrant comment créer plusieurs fiches avec des boutons de navigation qui passent de l'une à l'autre. Ces cartes peuvent être ajoutées à la pile contextuelle ou non contextuelle en poussant la carte renvoyée par createNavigationCard() dans un contexte particulier ou en dehors.

  /**
   *  Create the top-level card, with buttons leading to each of three
   *  'children' cards, as well as buttons to backtrack and return to the
   *  root card of the stack.
   *  @return {Card}
   */
  function createNavigationCard() {
    // Create a button set with actions to navigate to 3 different
    // 'children' cards.
    var buttonSet = CardService.newButtonSet();
    for(var i = 1; i <= 3; i++) {
      buttonSet.addButton(createToCardButton(i));
    }

    // Build the card with all the buttons (two rows)
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle('Navigation'))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()));
    return card.build();
  }

  /**
   *  Create a button that navigates to the specified child card.
   *  @return {TextButton}
   */
  function createToCardButton(id) {
    var action = CardService.newAction()
        .setFunctionName('gotoChildCard')
        .setParameters({'id': id.toString()});
    var button = CardService.newTextButton()
        .setText('Card ' + id)
        .setOnClickAction(action);
    return button;
  }

  /**
   *  Create a ButtonSet with two buttons: one that backtracks to the
   *  last card and another that returns to the original (root) card.
   *  @return {ButtonSet}
   */
  function buildPreviousAndRootButtonSet() {
    var previousButton = CardService.newTextButton()
        .setText('Back')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoPreviousCard'));
    var toRootButton = CardService.newTextButton()
        .setText('To Root')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoRootCard'));

    // Return a new ButtonSet containing these two buttons.
    return CardService.newButtonSet()
        .addButton(previousButton)
        .addButton(toRootButton);
  }

  /**
   *  Create a child card, with buttons leading to each of the other
   *  child cards, and then navigate to it.
   *  @param {Object} e object containing the id of the card to build.
   *  @return {ActionResponse}
   */
  function gotoChildCard(e) {
    var id = parseInt(e.parameters.id);  // Current card ID
    var id2 = (id==3) ? 1 : id + 1;      // 2nd card ID
    var id3 = (id==1) ? 3 : id - 1;      // 3rd card ID
    var title = 'CARD ' + id;

    // Create buttons that go to the other two child cards.
    var buttonSet = CardService.newButtonSet()
      .addButton(createToCardButton(id2))
      .addButton(createToCardButton(id3));

    // Build the child card.
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle(title))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()))
        .build();

    // Create a Navigation object to push the card onto the stack.
    // Return a built ActionResponse that uses the navigation object.
    var nav = CardService.newNavigation().pushCard(card);
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Pop a card from the stack.
   *  @return {ActionResponse}
   */
  function gotoPreviousCard() {
    var nav = CardService.newNavigation().popCard();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Return to the initial add-on card.
   *  @return {ActionResponse}
   */
  function gotoRootCard() {
    var nav = CardService.newNavigation().popToRoot();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }