Partager via


Créer une application d’onglet tableau de bord

Un tableau de bord est un outil permettant de suivre, d’analyser et d’afficher des données pour obtenir des informations sur une organisation ou un processus spécifique. Les tableaux de bord dans Teams vous permettent de surveiller et d’afficher des métriques importantes.

Le modèle d’onglet tableau de bord du Kit de ressources Teams vous permet de commencer à intégrer un canevas avec plusieurs cartes qui fournissent une vue d’ensemble du contenu dans Teams. Vous pouvez :

  • Utilisez des widgets pour afficher le contenu des applications et des services dans l’onglet de votre tableau de bord.
  • Intégrez votre application à l’API Graph pour visualiser des détails sur l’implémentation des données sélectionnées.
  • Créez des tableaux de bord personnalisables qui permettent à votre entreprise de définir des objectifs spécifiques qui vous aident à suivre les informations que vous devez afficher dans plusieurs domaines et entre les services.

Capture d’écran montrant l’exemple d’un tableau de bord.

Votre équipe peut obtenir les dernières mises à jour à partir de différentes sources dans Teams à l’aide de l’application d’onglet Tableau de bord Teams. Utilisez les applications d’onglet tableau de bord pour connecter de nombreuses métriques, sources de données, API et services. Les applications d’onglet tableau de bord aident votre entreprise à extraire des informations pertinentes à partir des sources et à les présenter aux utilisateurs. Pour plus d’informations sur la création d’une application d’onglet de tableau de bord, consultez le guide pas à pas.

Ajouter un nouveau tableau de bord

Après avoir créé une application d’onglet tableau de bord, vous pouvez ajouter un nouveau tableau de bord.

Pour ajouter un nouveau tableau de bord, procédez comme suit :

  1. Créer une classe de tableau de bord
  2. Remplacer les méthodes pour personnaliser l’application d’onglet de tableau de bord
  3. Ajouter un itinéraire pour la nouvelle application d’onglet tableau de bord
  4. Modifier le manifeste pour ajouter une nouvelle application d’onglet de tableau de bord

Créer une classe de tableau de bord

Créez un fichier avec l’extension .tsx pour votre tableau de bord dans le src/dashboards répertoire, par exemple . YourDashboard.tsx Ensuite, créez une classe qui étend le BaseDashboard class from
@microsoft/teamsfx-react.

//YourDashboard.tsx
import { BaseDashboard } from "@microsoft/teamsfx-react";

export default class YourDashboard extends BaseDashboard<any, any> {}

Remarque

Toutes les méthodes sont facultatives. Si vous ne remplacez aucune méthode, la disposition du tableau de bord par défaut est utilisée.

Remplacer les méthodes pour personnaliser l’application d’onglet de tableau de bord

La BaseDashboard classe fournit quelques méthodes que vous pouvez remplacer pour personnaliser la disposition du tableau de bord. Le tableau suivant répertorie les méthodes que vous pouvez remplacer :

Méthodes Fonction
styling() Personnalisez le style du tableau de bord.
layout() Définir la disposition des widgets.

Le code suivant est un exemple de personnalisation de la disposition du tableau de bord :

.your-dashboard-layout {
  grid-template-columns: 6fr 4fr;
}
import { BaseDashboard } from "@microsoft/teamsfx-react";
import ListWidget from "../widgets/ListWidget";
import ChartWidget from "../widgets/ChartWidget";

export default class YourDashboard extends BaseDashboard<any, any> {
  override styling(): string {
    return "your-dashboard-layout";
  }

  override layout(): JSX.Element | undefined {
    return (
      <>
        <ListWidget />
        <ChartWidget />
      </>
    );
  }
}

Ajouter un itinéraire pour la nouvelle application d’onglet tableau de bord

Vous devez lier votre widget à un fichier de source de données. Le widget récupère les données présentées dans le tableau de bord à partir du fichier source.

Ouvrez le src/App.tsx fichier et ajoutez un itinéraire pour le nouveau tableau de bord. Voici un exemple :

import YourDashboard from "./dashboards/YourDashboard";

export default function App() {
  ...
  <Route path="/yourdashboard" element={<YourDashboard />} />
  ...
}

Modifier le manifeste pour ajouter une nouvelle application d’onglet de tableau de bord

Ouvrez le appPackage/manifest.json fichier et ajoutez un nouvel onglet de tableau de bord sous staticTabs. Pour plus d'informations, voir app manifest Voici un exemple :

{
  "entityId": "index1",
  "name": "Your Dashboard",
  "contentUrl": "${{TAB_ENDPOINT}}/index.html#/yourdashboard",
  "websiteUrl": "${{TAB_ENDPOINT}}/index.html#/yourdashboard",
  "scopes": ["personal"]
}

Personnaliser la disposition du tableau de bord

TeamsFx fournit des méthodes pratiques pour définir et modifier la disposition du tableau de bord. Voici les méthodes :

  • Trois widgets d’une ligne avec une hauteur de 350 px occupant respectivement 20 %, 60 % et 20 % de la largeur.

    .customize-class-name {
      grid-template-rows: 350px;
      grid-template-columns: 2fr 6fr 2fr;
    }
    
    export default class SampleDashboard extends BaseDashboard<any, any> {
    
      override styling(): string {
        return "customize-class-name";
      }
    
      override layout(): JSX.Element | undefined {
        return (
          <>
           <ListWidget />
           <ChartWidget />
           <NewsWidget />
          </>
        );
      }
    }
    

    Capture d’écran montrant la disposition personnalisée du tableau de bord.

  • Deux widgets dans une ligne avec une largeur de 600 px et 1100 px. La hauteur de la première ligne est la hauteur maximale de son contenu, et la hauteur de la deuxième ligne est de 400 px.

    .customize-class-name {
      grid-template-rows: max-content 400px;
      grid-template-columns: 600px 1100px;
    }
    
        export default class SampleDashboard extends Dashboard {
      override styling(): string {
        return "customize-class-name";
      }
    
      override layout(): JSX.Element | undefined {
        return (
          <>
        <ListWidget />
        <ChartWidget />
        <NewsWidget />
          </>
        );
      }
        }
    

    Capture d’écran montrant la personnalisation de la hauteur et de la largeur de la disposition du tableau de bord.

  • Organisez deux widgets dans une colonne.

    .one-column {
        display: grid;
        gap: 20px;
        grid-template-rows: 1fr 1fr;
      }
    
      export default class SampleDashboard extends BaseDashboard<any, any> {
        override layout(): JSX.Element | undefined {
          return (
            <>
              <NewsWidget />
              <div className="one-column">
                <ListWidget />
                <ChartWidget />          
              </div>
            </>
          );
        }
      }
    

    Capture d’écran montrant la personnalisation à deux widgets.

Abstraction de l’application onglet Tableau de bord

Pour ajuster la disposition du tableau de bord, TeamsFx fournit une BaseDashboard classe permettant aux développeurs d’implémenter un tableau de bord.

Le code suivant est un exemple de BaseDashboard classe :

function dashboardStyle(isMobile?: boolean) {
  return mergeStyles({
    display: "grid",
    gap: "20px",
    padding: "20px",
    gridTemplateRows: "1fr",
    gridTemplateColumns: "4fr 6fr",
    ...(isMobile === true ? { gridTemplateColumns: "1fr", gridTemplateRows: "1fr" } : {}),
  });
}

interface BaseDashboardState {
  isMobile?: boolean;
  showLogin?: boolean;
  observer?: ResizeObserver;
}

export class BaseDashboard<P, S> extends Component<P, S & BaseDashboardState> {
  private ref: React.RefObject<HTMLDivElement>;

  public constructor(props: Readonly<P>) {
    super(props);
    this.state = {
      isMobile: undefined,
      showLogin: undefined,
      observer: undefined,
    } as S & BaseDashboardState;
    this.ref = React.createRef<HTMLDivElement>();
  }

  public async componentDidMount() {
    const observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        if (entry.target === this.ref.current) {
          const { width } = entry.contentRect;
          this.setState({ isMobile: width < 600 } as S & BaseDashboardState);
        }
      }
    });
    observer.observe(this.ref.current!);
  }

  public componentWillUnmount(): void {
    if (this.state.observer && this.ref.current) {
      this.state.observer.unobserve(this.ref.current);
    }
  }

  public render() {
    return (
      <div
        ref={this.ref}
        className={mergeStyles(dashboardStyle(this.state.isMobile), this.styling())}
      >
        {this.layout()}
      </div>
    );
  }

  protected layout(): JSX.Element | undefined {
    return undefined;
  }

  protected styling(): string {
    return null;
  }
}

Dans la BaseDashboard classe, TeamsFx fournit des dispositions de base avec des méthodes personnalisables. Le tableau de bord est toujours un composant react, et TeamsFx fournit des implémentations de base des fonctions basées sur le cycle de vie des composants react, comme :

  • Implémentation d’une logique de rendu de base basée sur la disposition de la grille.
  • Ajout d’un observateur pour s’adapter automatiquement aux appareils mobiles.

Voici les méthodes personnalisables à substituer :

Méthodes Fonction Recommander de remplacer
constructor() Initialise l’état et les variables du tableau de bord. Non
componentDidMount() Appelle une fois qu’un composant est monté. Non
componentWillUnmount() Appelle lorsqu’un composant est démontée. Non
render() Appelle en cas de mise à jour. La disposition par défaut du tableau de bord est définie dans cette méthode. Non
layout Définit la disposition du widget dans le tableau de bord. Vous pouvez remplacer cette méthode. Oui
styling() Pour personnaliser le style du tableau de bord. Vous pouvez remplacer cette méthode. Oui

Utiliser un widget dans votre tableau de bord

Les widgets affichent des informations et des graphiques configurables sur les tableaux de bord. Ils apparaissent sur le tableau des widgets où vous pouvez épingler, désépingler, organiser, redimensionner et personnaliser les widgets pour refléter vos centres d’intérêt. Votre tableau de widgets est optimisé pour afficher les widgets pertinents et le contenu personnalisé en fonction de votre utilisation.

Personnaliser le widget

Vous pouvez personnaliser le widget en remplaçant les méthodes suivantes dans la BaseWidget classe :

  • Remplacez header(), body()et footer() pour personnaliser le widget.

    export class NewsWidget extends BaseWidget<any, any> {
    override header(): JSX.Element | undefined {
    return (
      <div>
        <News28Regular />
        <Text>Your News</Text>
        <Button icon={<MoreHorizontal32Regular />} appearance="transparent" />
      </div>
    );
    }
    
    override body(): JSX.Element | undefined {
    return (
      <div>
        <Image src="image.svg" />
        <Text>Lorem Ipsum Dolor</Text>
        <Text>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim,
          elementum sed
        </Text>
      </div>
    );
    }
    
    override footer(): JSX.Element | undefined {
    return (
      <Button
        appearance="transparent"
        icon={<ArrowRight16Filled />}
        iconPosition="after"
        size="small"
      >
        View details
      </Button>
    );
    }
    }
    

    Capture d’écran montrant l’exemple de contenu d’en-tête, de corps et de pied de page dans un widget.

  • Remplacez body() et footer() pour personnaliser le widget.

    export class NewsWidget extends BaseWidget<any, any> {
    override body(): JSX.Element | undefined {
    return (
      <div>
        <Image src="image.svg" />
        <Text>Lorem Ipsum Dolor</Text>
        <Text>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim,
          elementum sed
        </Text>
      </div>
    );
    }
    
    override footer(): JSX.Element | undefined {
    return (
      <Button
        appearance="transparent"
        icon={<ArrowRight16Filled />}
        iconPosition="after"
        size="small"
      >
        View details
      </Button>
    );
    }
    }
    

    Capture d’écran montrant le contenu du corps et du pied de page dans un widget.

  • Remplacer body() pour personnaliser le widget.

    export class NewsWidget extends BaseWidget<any, any> {
    override body(): JSX.Element | undefined {
    return (
      <div>
        <Image src="image.svg" />
        <Text>Lorem Ipsum Dolor</Text>
        <Text>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Enim,
          elementum sed
        </Text>
      </div>
    );
    }
    }
    

    Capture d’écran montrant le contenu du corps dans un widget.

Inclure un chargeur de données

Si vous souhaitez inclure un chargeur de données dans votre widget avant le chargement du widget, vous pouvez ajouter une propriété à l’état du widget pour indiquer que le chargeur de données est loading(). Vous pouvez utiliser cette propriété pour afficher un indicateur de chargement à l’utilisateur.

Exemple :

    override loading(): JSX.Element | undefined {
     return (
      <div className="loading">
       <Spinner label="Loading..." labelPosition="below" />
      </div>
     );
    }

À présent, le spinner de chargement s’affiche pendant le chargement des données. Lorsque les données sont chargées, le chargeur de chargement est masqué et les données de liste et le bouton pied de page s’affichent.

La représentation graphique montre le spinner de chargement pendant le chargement des données.

Gérer l’état vide

Vous pouvez afficher un contenu spécifique dans votre widget lorsque les données sont vides. Pour ce faire, vous devez modifier la body méthode dans votre fichier de widget afin d’adopter différents états des données.

L’exemple suivant montre comment afficher une image vide lorsque les données de ListWidget sont vides .

override body(): JSX.Element | undefined {
  let hasData = this.state.data && this.state.data.length > 0;
  return (
    <div>
      {hasData ? (
        <>
          {this.state.data?.map((t: ListModel) => {
            ...
          })}
        </>
      ) : (
        <div>
          <Image src="empty-default.svg" height="150px" />
          <Text align="center">No data</Text>
        </div>
      )}
    </div>
  );
}

Vous pouvez utiliser une approche similaire pour supprimer le contenu du pied de page de votre widget lorsque les données sont vides.

  override footer(): JSX.Element | undefined {
    let hasData = this.state.data && this.state.data.length > 0;
    if (hasData) {
      return <Button>...</Button>;
    }
  }

Lorsque les données sont vides, votre widget de liste s’affiche comme suit :

Capture d’écran montrant aucune donnée dans la liste.

Actualiser les données comme prévu

L’exemple suivant montre comment afficher des données en temps réel dans un widget. Le widget affiche l’heure actuelle et les mises à jour.

interface IRefreshWidgetState {
  data: string;
}

export class RefreshWidget extends BaseWidget<any, IRefreshWidgetState> {
  override body(): JSX.Element | undefined {
    return <>{this.state.data}</>;
  }

  async componentDidMount() {
    setInterval(() => {
      this.setState({ data: new Date().toLocaleTimeString() });
    }, 1000);
  }
}

Vous pouvez modifier setInterval la méthode pour appeler votre propre fonction afin d’actualiser les données comme celle-ci setInterval(() => yourGetDataFunction(), 1000).

Abstraction de widget

Pour simplifier le développement d’un widget, le Kit de développement logiciel (SDK) TeamsFx fournit une BaseWidget classe permettant aux développeurs d’hériter pour implémenter un widget qui répond à leurs besoins sans prêter beaucoup d’attention à implémenter la disposition du widget.

Le code suivant est un exemple de classe BaseWidget :

export interface IWidgetClassNames {
  root?: string;
  header?: string;
  body?: string;
  footer?: string;
}

const classNames: IWidgetClassNames = mergeStyleSets({
  root: {
    display: "grid",
    padding: "1.25rem 2rem 1.25rem 2rem",
    backgroundColor: tokens.colorNeutralBackground1,
    border: "1px solid var(--colorTransparentStroke)",
    boxShadow: tokens.shadow4,
    borderRadius: tokens.borderRadiusMedium,
    gap: tokens.spacingHorizontalL,
    gridTemplateRows: "max-content 1fr max-content",
  },
  header: {
    display: "grid",
    height: "max-content",
    "& div": {
      display: "grid",
      gap: tokens.spacingHorizontalS,
      alignItems: "center",
      gridTemplateColumns: "min-content 1fr min-content",
    },
    "& svg": {
      height: "1.5rem",
      width: "1.5rem",
    },
    "& span": {
      fontWeight: tokens.fontWeightSemibold,
      lineHeight: tokens.lineHeightBase200,
      fontSize: tokens.fontSizeBase200,
    },
  },
  footer: {
    "& button": {
      width: "fit-content",
    },
  },
});

interface BaseWidgetState {
  loading?: boolean;
}

export class BaseWidget<P, S> extends Component<P, S & BaseWidgetState> {
  public constructor(props: Readonly<P>) {
    super(props);
    this.state = { loading: undefined } as S & BaseWidgetState;
  }

  public async componentDidMount() {
    this.setState({ ...(await this.getData()), loading: false });
  }

  public render() {
    const { root, header, body, footer } = this.styling();
    const showLoading = this.state.loading !== false && this.loading() !== undefined;
    return (
      <div className={mergeStyles(classNames.root, root)}>
        {this.header() && (
          <div className={mergeStyles(classNames.header, header)}>{this.header()}</div>
        )}
        {showLoading ? (
          this.loading()
        ) : (
          <>
            {this.body() !== undefined && <div className={body}>{this.body()}</div>}
            {this.footer() !== undefined && (
              <div className={mergeStyles(classNames.footer, footer)}>{this.footer()}</div>
            )}
          </>
        )}
      </div>
    );
  }

  protected async getData(): Promise<S> {
    return undefined;
  }

  protected header(): JSX.Element | undefined {
    return undefined;
  }

  protected body(): JSX.Element | undefined {
    return undefined;
  }

  protected footer(): JSX.Element | undefined {
    return undefined;
  }

  protected loading(): JSX.Element | undefined {
    return undefined;
  }

  protected styling(): IWidgetClassNames {
    return {};
  }
}

Voici les méthodes recommandées à substituer :

Méthodes Fonction Recommander de remplacer
constructor() Appelle l’initial this.state et appelle le constructeur de la super classe React.Component. Non
componentDidMount() Appelle une fois qu’un composant est monté et affecte une valeur à la data propriété de l’état en appelant la getData() méthode . Non
render() Appelle chaque fois qu’il y a une mise à jour. La disposition par défaut du tableau de bord est définie dans cette méthode. Non
getData() Appelle les données nécessaires au widget. La valeur retournée par cette méthode est définie sur this.state.data. Oui
header() Appelle à quoi ressemble l’en-tête du widget. Vous pouvez choisir de remplacer cette méthode pour personnaliser un widget ou non, si ce n’est pas le cas, le widget n’aura pas d’en-tête. Oui
body() Appelle à quoi ressemble le corps du widget. Vous pouvez choisir de remplacer cette méthode pour personnaliser un widget ou non, si ce n’est pas le cas, le widget n’aura pas de corps. Oui
footer() Appelle à quoi ressemble le pied de page du widget. Vous pouvez choisir de remplacer cette méthode pour personnaliser un widget ou non, si ce n’est pas le cas, le widget n’aura pas de pied de page. Oui
loading() Appelle lorsque le widget est en cours d’extraction de données. Si un indicateur de chargement est requis, la méthode peut retourner un JSX.Element qui contient les composants nécessaires pour afficher l’indicateur de chargement. Oui
style() Appelle un objet qui définit les noms de classe pour les différentes parties du widget. Oui

Microsoft Graph Toolkit en tant que contenu de widget

Le Kit de ressources Microsoft Graph est un ensemble de composants web renouvelables et indépendants de l’infrastructure, qui permet d’accéder à Microsoft Graph et de l’utiliser. Vous pouvez utiliser le Kit de ressources Microsoft Graph avec n’importe quel framework web ou sans framework.

Pour utiliser le Kit de ressources Microsoft Graph comme contenu de widget, procédez comme suit :

  1. Ajouter une fonctionnalité d’authentification unique à votre application Teams : Microsoft Teams fournit la fonction d’authentification unique (SSO) pour qu’une application obtienne un jeton d’utilisateur Teams connecté pour accéder à Microsoft Graph. Pour plus d’informations, reportez-vous à la fonctionnalité D’authentification unique pour votre application Teams.

  2. Installez les packages requis npm .

    Exécutez la commande suivante dans votre dossier de projet tabs pour installer les packages requis npm :

    npm install @microsoft/mgt-react @microsoft/mgt-teamsfx-provider
    
  3. Ajouter un widget Graph Toolkit : créez un fichier de widget dans le dossier de votre projetsrc/views/widgets, par exemple. GraphWidget.tsx Dans ce widget, nous allons guider les utilisateurs à donner leur consentement à notre application pour accéder à Microsoft Graph, puis afficher la liste des tâches de l’utilisateur à l’aide du Kit de ressources Microsoft Graph.

    Le code suivant est un exemple d’utilisation du composant Todo de Microsoft Graph Toolkit dans le widget :

    import { Providers, ProviderState, Todo } from "@microsoft/mgt-react";
    import { TeamsFxProvider } from "@microsoft/mgt-teamsfx-provider";
    
    import { loginAction } from "../../internal/login";
    import { TeamsUserCredentialContext } from "../../internal/singletonContext";
    import { BaseWidget } from "@microsoft/teamsfx-react";
    
    interface IGraphWidgetState {
      needLogin: boolean;
    }
    
    export class GraphWidget extends Widget<any, IGraphWidgetState> {
      override body(): JSX.Element | undefined {
        return <div>{this.state.needLogin === false && <Todo />}</div>;
      }
    
      async componentDidMount() {
        super.componentDidMount();
    
        // Initialize TeamsFx provider
        const provider = new TeamsFxProvider(TeamsUserCredentialContext.getInstance().getCredential(), [
         "Tasks.ReadWrite",
    ]);
        Providers.globalProvider = provider;
    
        // Check if user is signed in
        if (await this.checkIsConsentNeeded()) {
          await loginAction(["Tasks.ReadWrite"]);
    }
    
    // Update signed in state
    Providers.globalProvider.setState(ProviderState.SignedIn);
    this.setState({ needLogin: false });
    
      }
    
      /**
    
      * Check if user needs to consent
      * @returns true if user needs to consent
      */
    
      async checkIsConsentNeeded() {
        let needConsent = false;
        try {
          await TeamsUserCredentialContext.getInstance().getCredential().getToken(["Tasks.ReadWrite"]);
        } catch (error) {
          needConsent = true;
        }
        return needConsent;
      }
    }
    

    Vous pouvez utiliser d’autres composants du Kit de ressources Microsoft Graph dans votre widget. Pour plus d’informations, consultez Kit de ressources Microsoft Graph.

  4. Ajoutez le widget à la disposition du tableau de bord. Incluez le nouveau widget dans votre fichier de tableau de bord.

    ...
    export default class YourDashboard extends BaseDashboard<any, any> {
      ...
      override layout(): undefined | JSX.Element {
        return (
          <>
            <GraphWiget />
          </>
        );
      }
      ...
    }
    

Maintenant, lancez ou actualisez votre application Teams. Vous verrez le nouveau widget à l’aide du Kit de ressources Microsoft Graph.

Appel d’API Graph

L’API Microsoft Graph est une API web que vous pouvez utiliser pour communiquer avec le cloud Microsoft et d’autres services. Les applications personnalisées peuvent utiliser l’API de Microsoft Graph pour se connecter à des données et les utiliser dans des applications personnalisées pour améliorer la productivité organisationnelle.

Avant d’implémenter votre logique d’appel d’API Graph, il est nécessaire d’activer l’authentification unique pour votre projet de tableau de bord. Pour plus d’informations, consultez Ajouter l’authentification unique à l’application Teams.

Pour ajouter un appel d’API Graph :

Appeler l’API Graph à partir du front-end (utiliser des autorisations déléguées)

Si vous souhaitez appeler une API Graph à partir de l’onglet front-end, procédez comme suit :

  1. Pour obtenir le nom de l’étendue d’autorisation associée à l’API Graph que vous envisagez d’appeler, consultez API Graph.

  2. Créez un client Graph en ajoutant l’étendue associée à l’API Graph que vous souhaitez appeler.

    let credential: TeamsUserCredential;  
    credential = TeamsUserCredentialContext.getInstance().getCredential();
    const graphClient: Client = createMicrosoftGraphClientWithCredential(credential, scope);
    
  3. Appelez l’API Graph et analysez la réponse dans un certain modèle.

    try {
      const graphApiResult = await graphClient.api("<GRAPH_API_PATH>").get();
      // Parse the graphApiResult into a Model you defined, used by the front-end.
    } catch (e) {}
    

Appeler l’API Graph à partir du back-end (utiliser les autorisations d’application)

Si vous souhaitez appeler une API Graph à partir du back-end, procédez comme suit :

  1. Autorisations d’application de consentement
  2. Ajouter une fonction Azure
  3. Ajouter votre logique dans la fonction Azure
  4. Appeler la fonction Azure à partir du front-end

Pour donner votre consentement aux autorisations d’application, procédez comme suit :

  1. Accédez au portail Azure.
  2. Sélectionnez ID Microsoft Entra.
  3. Sélectionnez Inscriptions d’applications dans le volet gauche.
  4. Sélectionnez votre application de tableau de bord.
  5. Sélectionnez Autorisations d’API dans le volet gauche.
  6. Sélectionnez Ajouter une autorisation.
  7. Sélectionnez Microsoft Graph.
  8. Sélectionnez Autorisations d’application.
  9. Recherchez les autorisations dont vous avez besoin.
  10. Sélectionnez le bouton Ajouter des autorisations en bas.
  11. Sélectionnez ✔Accorder le consentement de l’administrateur.
  12. Sélectionnez le bouton Oui pour terminer le consentement de l’administrateur.

Ajouter une fonction Azure

Dans le volet gauche de Visual Studio Code, accédez à Teams Toolkit>Ajout de fonctionnalités>Azure Functions et entrez le nom de la fonction.

Capture d’écran montrant la sélection d’Azure Functions.

Pour plus d’informations sur l’ajout d’une fonction Azure à votre projet, consultez Intégrer Azure Functions à votre application Teams.

Ajouter votre logique dans la fonction Azure

Dans le index.ts/index.ts dossier nommé Azure Function, vous pouvez ajouter votre logique qui contient l’appel de l’API Graph principale avec des autorisations d’application. Reportez-vous à l’extrait de code suivant :

/**
 * This function handles requests from teamsfx client.
 * The HTTP request should contain an SSO token queried from Teams in the header.
 * Before triggering this function, teamsfx binding would process the SSO token and generate teamsfx configuration.
 *
 * You should initializes the teamsfx SDK with the configuration and calls these APIs.
 *
 * The response contains multiple message blocks constructed into a JSON object, including:
 * - An echo of the request body.
 * - The display name encoded in the SSO token.
 * - Current user's Microsoft 365 profile if the user has consented.
 *
 * @param {Context} context - The Azure Functions context object.
 * @param {HttpRequest} req - The HTTP request.
 * @param {teamsfxContext} TeamsfxContext - The context generated by teamsfx binding.
 */
export default async function run(
  context: Context,
  req: HttpRequest,
  teamsfxContext: TeamsfxContext
): Promise<Response> {
  context.log("HTTP trigger function processed a request.");

  // Initialize response.
  const res: Response = {
    status: 200,
    body: {},
  };

  // Your logic here.

  return res;
}

Appeler la fonction Azure à partir du front-end

Appelez la fonction Azure par nom de fonction. Reportez-vous à l’extrait de code suivant pour appeler la fonction Azure :

const functionName = process.env.REACT_APP_FUNC_NAME || "myFunc";
export let taskName: string;

export async function callFunction(params?: string) {
  taskName = params || "";
  const credential = TeamsUserCredentialContext.getInstance().getCredential();
  if (!credential) {
    throw new Error("TeamsFx SDK is not initialized.");
  }
  try {
    const apiBaseUrl = process.env.REACT_APP_FUNC_ENDPOINT + "/api/";    
    const apiClient = createApiClient(
      apiBaseUrl,
      new BearerTokenAuthProvider(async () => (await credential.getToken(""))!.token)
    );
    const response = await apiClient.get(functionName);
    return response.data;
  } catch (err: unknown) {
    ...
  }
}

Pour plus d’informations, reportez-vous aux rubriques suivantes :

Incorporer Power BI au tableau de bord

Pour incorporer Power BI au tableau de bord, consultez Réaction du client Power BI.

Guide pas à pas

Suivez le guide pas à pas pour créer un tableau de bord et découvrez comment ajouter un widget et un appel d’API Graph au tableau de bord.

Voir aussi