Share via


Compilación de una aplicación de pestaña de panel

Un panel es una herramienta para realizar un seguimiento, analizar y mostrar datos para obtener información sobre una organización o un proceso específico. Los paneles de Teams permiten supervisar y ver métricas importantes.

La plantilla de pestaña panel del kit de herramientas de Teams le permite empezar a integrar un lienzo con varias tarjetas que proporcionan información general sobre el contenido en Teams. Puede:

  • Use widgets para mostrar contenido de aplicaciones y servicios en la pestaña del panel.
  • Integre la aplicación con Graph API para visualizar detalles sobre la implementación de los datos seleccionados.
  • Cree paneles personalizables que permitan a su empresa establecer objetivos específicos que le ayuden a realizar un seguimiento de la información que necesita ver en varias áreas y entre departamentos.

Captura de pantalla que muestra el ejemplo de un panel.

El equipo puede obtener las actualizaciones más recientes de diferentes orígenes en Teams mediante la aplicación de pestaña panel de Teams. Use aplicaciones de pestaña de panel para conectar numerosas métricas, orígenes de datos, API y servicios. Las aplicaciones de pestaña del panel ayudan a su empresa a extraer información relevante de los orígenes y a presentarla a los usuarios. Para obtener más información sobre cómo crear una aplicación de pestaña de panel, consulte la guía paso a paso.

Agregar un nuevo panel

Después de crear una aplicación de pestaña de panel, puede agregar un nuevo panel.

Para agregar un nuevo panel, siga estos pasos:

  1. Creación de una clase de panel
  2. Invalidar métodos para personalizar la aplicación de pestaña del panel
  3. Agregar una ruta para la nueva aplicación de pestaña de panel
  4. Modificación del manifiesto para agregar una nueva aplicación de pestaña de panel

Creación de una clase de panel

Cree un archivo con la .tsx extensión del panel en el src/dashboards directorio, por ejemplo, YourDashboard.tsx. A continuación, cree una clase que extienda el BaseDashboard class from
@microsoft/teamsfx-react.

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

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

Nota:

Todos los métodos son opcionales. Si no invalida ningún método, se usa el diseño de panel predeterminado.

Invalidar métodos para personalizar la aplicación de pestaña del panel

La BaseDashboard clase proporciona algunos métodos que puede invalidar para personalizar el diseño del panel. En la tabla siguiente se enumeran los métodos que puede invalidar:

Métodos Función
styling() Personalice el estilo del panel.
layout() Definir el diseño de widgets.

El código siguiente es un ejemplo para personalizar el diseño del panel:

.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 />
      </>
    );
  }
}

Agregar una ruta para la nueva aplicación de pestaña de panel

Debe vincular el widget a un archivo de origen de datos. El widget recoge los datos que se presentan en el panel desde el archivo de origen.

Abra el src/App.tsx archivo y agregue una ruta para el nuevo panel. Aquí le mostramos un ejemplo:

import YourDashboard from "./dashboards/YourDashboard";

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

Modificación del manifiesto para agregar una nueva aplicación de pestaña de panel

Abra el appPackage/manifest.json archivo y agregue una nueva pestaña de panel en staticTabs. Para obtener más información, vea manifiesto de aplicación. Aquí le mostramos un ejemplo:

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

Personalización del diseño del panel

TeamsFx proporciona métodos prácticos para definir y modificar el diseño del panel. Estos son los métodos:

  • Tres widgets en una fila con el alto de 350 px ocupando el 20 por ciento, el 60 por ciento y el 20 por ciento del ancho, respectivamente.

    .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 />
          </>
        );
      }
    }
    

    Captura de pantalla que muestra el diseño personalizado del panel.

  • Dos widgets en una fila con un ancho de 600 px y 1100 px. El alto de la primera línea es el alto máximo de su contenido y el alto de la segunda línea es 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 />
          </>
        );
      }
        }
    

    Captura de pantalla que muestra la personalización de alto y ancho del diseño del panel.

  • Organice dos widgets en una columna.

    .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>
            </>
          );
        }
      }
    

    Captura de pantalla que muestra la personalización de dos widgets.

Abstracción de la aplicación de pestaña panel

Para ajustar el diseño del panel, TeamsFx proporciona una BaseDashboard clase para que los desarrolladores implementen un panel.

El código siguiente es un ejemplo de una BaseDashboard clase:

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;
  }
}

En la BaseDashboard clase, TeamsFx proporciona diseños básicos con métodos personalizables. El panel sigue siendo un componente react y TeamsFx proporciona implementaciones básicas de funciones basadas en el ciclo de vida de los componentes react, como:

  • Implementación de una lógica de representación básica basada en el diseño de cuadrícula.
  • Agregar un observador para adaptarse automáticamente a los dispositivos móviles.

A continuación se muestran los métodos personalizables para invalidar:

Métodos Función Recomendación para invalidar
constructor() Inicializa el estado del panel y las variables. No
componentDidMount() Invoca después de montar un componente. No
componentWillUnmount() Invoca cuando se desmonta un componente. No
render() Invoca cuando hay una actualización. El diseño predeterminado del panel se define en este método. No
layout Define el diseño del widget en el panel. Puede invalidar este método.
styling() Para personalizar el estilo del panel. Puede invalidar este método.

Uso de un widget en el panel

Los widgets muestran información configurable y gráficos en los paneles. Aparecen en el panel de widgets, donde puede anclar, desanclar, organizar, cambiar el tamaño y personalizar widgets para reflejar sus intereses. El panel de widgets está optimizado para mostrar widgets relevantes y contenido personalizado en función de su uso.

Personalización del widget

Puede personalizar el widget reemplazando los métodos siguientes en la BaseWidget clase :

  • Invalide header(), body()y footer() para personalizar el 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>
    );
    }
    }
    

    Captura de pantalla que muestra el ejemplo de contenido de encabezado, cuerpo y pie de página en un widget.

  • Invalide body() y footer() para personalizar el 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>
    );
    }
    }
    

    Captura de pantalla que muestra el contenido del cuerpo y el pie de página en un widget.

  • Invalide body() para personalizar el 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>
    );
    }
    }
    

    Captura de pantalla que muestra el contenido del cuerpo en un widget.

Incluir un cargador de datos

Si desea incluir un cargador de datos en el widget antes de cargar el widget, puede agregar una propiedad al estado del widget para indicar que el cargador de datos es loading(). Puede usar esta propiedad para mostrar un indicador de carga al usuario.

Ejemplo:

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

Ahora, se muestra el spinner de carga mientras se cargan los datos. Cuando se cargan los datos, el spinner de carga está oculto y se muestran los datos de lista y el botón de pie de página.

La representación gráfica muestra el spinner de carga mientras se cargan los datos.

Controlar el estado vacío

Puede mostrar un contenido específico en el widget cuando los datos están vacíos. Para ello, debe modificar el método en el body archivo de widget para adoptar diferentes estados de los datos.

En el ejemplo siguiente se muestra cómo mostrar una imagen vacía cuando los datos de ListWidget están vacíos .

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>
  );
}

Puede usar un enfoque similar para quitar el contenido del pie de página del widget cuando los datos están vacíos.

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

Cuando los datos están vacíos, el widget de lista aparece de la siguiente manera:

Captura de pantalla que muestra que no hay datos en la lista.

Actualizar datos según lo programado

En el ejemplo siguiente se muestra cómo mostrar datos en tiempo real en un widget. El widget muestra la hora actual y las actualizaciones.

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);
  }
}

Puede modificar setInterval el método para llamar a su propia función para actualizar datos como este setInterval(() => yourGetDataFunction(), 1000).

Abstracción de widget

Para simplificar el desarrollo de un widget, el SDK de TeamsFx proporciona una BaseWidget clase para que los desarrolladores hereden para implementar un widget que satisfaga sus necesidades sin prestar mucha atención a la implementación del diseño del widget.

El código siguiente es un ejemplo de la clase 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 {};
  }
}

Los siguientes son los métodos recomendados para invalidar:

Métodos Función Recomendación para invalidar
constructor() Invoca la inicial this.state y llama al constructor de la superclase React.Component. No
componentDidMount() Invoca después de montar un componente y asigna un valor a la data propiedad del estado llamando al getData() método . No
render() Invoca cada vez que hay una actualización. El diseño predeterminado del panel se define en este método. No
getData() Invoca los datos necesarios para el widget. El valor devuelto por este método se establece en this.state.data.
header() Invoca el aspecto del encabezado del widget. Puede optar por invalidar este método para personalizar un widget o no, si no es así, el widget no tendrá un encabezado.
body() Invoca el aspecto del cuerpo del widget. Puede optar por invalidar este método para personalizar un widget o no, si no es así, el widget no tendrá un cuerpo.
footer() Invoca el aspecto del pie de página del widget. Puede optar por invalidar este método para personalizar un widget o no, si no es así, el widget no tendrá un pie de página.
loading() Invoca cuando el widget está en proceso de captura de datos. Si se requiere un indicador de carga, el método puede devolver un JSX.Element que contenga los componentes necesarios para representar el indicador de carga.
style() Invoca un objeto que define los nombres de clase para las distintas partes del widget.

Microsoft Graph Toolkit como contenido de widget

Microsoft Graph Toolkit es un conjunto de componentes web renovables independientes del marco, que ayuda a acceder y trabajar con Microsoft Graph. Puede usar el kit de herramientas de Microsoft Graph con cualquier marco web o sin un marco.

Para usar Microsoft Graph Toolkit como contenido del widget, siga estos pasos:

  1. Agregar la característica sso a la aplicación de Teams: Microsoft Teams proporciona una función de inicio de sesión único (SSO) para que una aplicación obtenga el token de usuario de Teams que ha iniciado sesión para acceder a Microsoft Graph. Para obtener más información, consulte la característica sso a la aplicación de Teams.

  2. Instale los paquetes necesarios npm .

    Ejecute el siguiente comando en la carpeta del proyecto tabs para instalar los paquetes necesarios npm :

    npm install @microsoft/mgt-react @microsoft/mgt-teamsfx-provider
    
  3. Agregar un nuevo widget de Graph Toolkit: cree un nuevo archivo de widget en la carpeta del proyecto src/views/widgets , por ejemplo, GraphWidget.tsx. En este widget, guiaremos a los usuarios para dar su consentimiento a nuestra aplicación para acceder a Microsoft Graph y, a continuación, mostrar la lista todo del usuario mediante Microsoft Graph Toolkit.

    El código siguiente es un ejemplo de uso del componente Todo del kit de herramientas de Microsoft Graph en el 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;
      }
    }
    

    Puede usar componentes alternativos del kit de herramientas de Microsoft Graph en el widget. Para obtener más información, consulte Microsoft Graph Toolkit.

  4. Agregue el widget al diseño del panel. Incluya el nuevo widget en el archivo del panel.

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

Ahora, inicie o actualice la aplicación de Teams, verá el nuevo widget con Microsoft Graph Toolkit.

llamada Graph API

Microsoft Graph API es una API web que puede usar para comunicarse con la nube de Microsoft y otros servicios. Las aplicaciones personalizadas pueden usar la API de Microsoft Graph para conectarse a los datos y usarla en aplicaciones personalizadas para mejorar la productividad de la organización.

Antes de implementar la lógica de llamadas de Graph API, es necesario habilitar el inicio de sesión único para el proyecto de panel. Para obtener más información, consulte Agregar inicio de sesión único a la aplicación Teams.

Para agregar una llamada Graph API:

Llamar a Graph API desde el front-end (usar permisos delegados)

Si desea llamar a un Graph API desde la pestaña front-end, siga estos pasos:

  1. Para obtener el nombre del ámbito de permiso asociado a la Graph API que va a invocar, consulte Graph API.

  2. Cree un cliente de Graph agregando el ámbito relacionado con el Graph API al que desea llamar.

    let credential: TeamsUserCredential;  
    credential = TeamsUserCredentialContext.getInstance().getCredential();
    const graphClient: Client = createMicrosoftGraphClientWithCredential(credential, scope);
    
  3. Llame al Graph API y analice la respuesta en un modelo determinado.

    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) {}
    

Llamar a Graph API desde el back-end (usar permisos de aplicación)

Si desea llamar a un Graph API desde el back-end, siga estos pasos:

  1. Permisos de aplicación de consentimiento
  2. Adición de una función de Azure
  3. Incorporación de la lógica en la función de Azure
  4. Llamada a la función de Azure desde el front-end

Para dar su consentimiento a los permisos de aplicación, siga estos pasos:

  1. Acceda a Portal Azure.
  2. Seleccione Microsoft Entra id.
  3. Seleccione Registros de aplicaciones en el panel izquierdo.
  4. Seleccione la aplicación de panel.
  5. Seleccione Permisos de API en el panel izquierdo.
  6. Seleccione Agregar permiso.
  7. Seleccione Microsoft Graph.
  8. Seleccione Permisos de aplicación.
  9. Busque los permisos que necesita.
  10. Seleccione el botón Agregar permisos en la parte inferior.
  11. Seleccione ✔Conceder consentimiento de administrador.
  12. Seleccione el botón para finalizar el consentimiento del administrador.

Adición de una función de Azure

En el panel izquierdo de la Visual Studio Code, vaya a Teams Toolkit>Adding features Azure Functions (Agregar características>Azure Functions y escriba el nombre de la función.

Captura de pantalla que muestra la selección de Azure Functions.

Para obtener más información sobre cómo agregar una función de Azure al proyecto, consulte Integración de Azure Functions con la aplicación de Teams.

Incorporación de la lógica en la función de Azure

En la index.ts/index.ts carpeta denominada Función de Azure, puede agregar la lógica que contiene el back-end Graph API llamadas con permisos de aplicación. Consulte el siguiente fragmento de código:

/**
 * 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;
}

Llamada a la función de Azure desde el front-end

Llame a la función de Azure por nombre de función. Consulte el siguiente fragmento de código para llamar a la función de 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) {
    ...
  }
}

Para obtener más información, consulte:

Inserción de Power BI en el panel

Para insertar Power BI en el panel, consulte Reacción del cliente de Power BI.

Guía paso a paso

Siga la guía paso a paso para crear un panel y aprenda a agregar un widget y Graph API llamada al panel.

Vea también