Erstellen von auf React basierten Single-Page-Apps mit Microsoft Graph
In diesem Lernprogramm erfahren Sie, wie Sie eine React einzelseitige App erstellen, die die Microsoft Graph-API zum Abrufen von Kalenderinformationen für einen Benutzer verwendet.
Tipp
Wenn Sie es vorziehen, nur das abgeschlossene Lernprogramm herunterzuladen, können Sie das GitHub Repository herunterladen oder klonen.
Voraussetzungen
Bevor Sie mit diesem Lernprogramm beginnen, sollten SieNode.js und Yarn auf Ihrem Entwicklungscomputer installiert haben. Wenn Sie nicht über Node.js oder Yarn verfügen, finden Sie unter den vorherigen Links Downloadoptionen.
Sie sollten auch über ein persönliches Microsoft-Konto mit einem Postfach auf Outlook.com oder ein Microsoft-Geschäfts-, Schul- oder Unikonto verfügen. Wenn Sie kein Microsoft-Konto haben, gibt es einige Optionen, um ein kostenloses Konto zu erhalten:
- Sie können sich für ein neues persönliches Microsoft-Konto registrieren.
- Sie können sich für das Microsoft 365-Entwicklerprogramm registrieren, um ein kostenloses Microsoft 365 Abonnement zu erhalten.
Hinweis
Dieses Lernprogramm wurde mit Node Version 14.15.0 und Yarn Version 1.22.10 geschrieben. Die Schritte in diesem Handbuch funktionieren möglicherweise mit anderen Versionen, die jedoch nicht getestet wurden.
Feedback
Bitte geben Sie Feedback zu diesem Lernprogramm im GitHub Repository.
Erstellen einer auf React basierten Single-Page-App
In diesem Abschnitt erstellen Sie eine neue React-App.
Öffnen Sie die Befehlszeilenschnittstelle (CLI), navigieren Sie zu einem Verzeichnis, in dem Sie über die Berechtigung zum Erstellen von Dateien verfügen, und führen Sie die folgenden Befehle aus, um eine neue React App zu erstellen.
yarn create react-app graph-tutorial --template typescript
Wechseln Sie nach Abschluss des Befehls zum Verzeichnis "** des Graph-Lernprogramms in Ihrer CLI, und führen Sie den folgenden Befehl aus, um einen lokalen Webserver zu starten.
yarn start
Hinweis
Wenn Sie Yarn nicht installiert haben, können Sie
npm start
es stattdessen verwenden.
Ihr Standardbrowser wird https://localhost:3000/ mit einer standardmäßigen React Seite geöffnet. Wenn Ihr Browser nicht geöffnet wird, öffnen Sie ihn, und navigieren https://localhost:3000/ Sie, um zu überprüfen, ob die neue App funktioniert.
Hinzufügen von Node-Paketen
Bevor Sie fortfahren, installieren Sie einige zusätzliche Pakete, die Sie später verwenden werden:
- react-router-dom für deklaratives Routing innerhalb der React-App.
- bootstrap für Formatierung und allgemeine Komponenten.
- react-bootstrap für React Komponenten, die auf Bootstrap basieren.
- date-fns formatting dates and times.
- windows-iana zum Übersetzen Windows Zeitzonen in das IANA-Format.
- msal-react für die Authentifizierung bei Azure Active Directory und das Abrufen von Zugriffstoken.
- microsoft-graph-client for making calls to Microsoft Graph.
Führen Sie den folgenden Befehl in Der CLI aus.
yarn add react-router-dom@5.2.0 bootstrap@5.0.1 react-bootstrap@2.0.0-beta.4 windows-iana@5.0.2
yarn add date-fns@2.22.1 date-fns-tz@1.1.4 @azure/msal-react@1.0.1 @azure/msal-browser@2.16.1 @microsoft/microsoft-graph-client@3.0.0
yarn add -D @types/react-router-dom@5.1.8 @types/microsoft-graph
Entwerfen der App
Erstellen Sie zunächst einen Kontext für die App.
Erstellen Sie eine neue Datei im Verzeichnis ./src mit dem Namen "AppContext.tsx", und fügen Sie die folgenden
import
Anweisungen hinzu.import React, { useContext, createContext, useState, MouseEventHandler, useEffect} from 'react'; import { AuthCodeMSALBrowserAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/authCodeMsalBrowser'; import { InteractionType, PublicClientApplication } from '@azure/msal-browser'; import { useMsal } from '@azure/msal-react';
Fügen Sie den folgenden Code hinzu.
Fügen Sie die folgende Funktion am Ende von ./src/AppContext.tsx hinzu.
function useProvideAppContext() { const [user, setUser] = useState<AppUser | undefined>(undefined); const [error, setError] = useState<AppError | undefined>(undefined); const displayError = (message: string, debug?: string) => { setError({message, debug}); } const clearError = () => { setError(undefined); } const authProvider = undefined; const signIn = async () => { // TODO }; const signOut = async () => { // TODO }; return { user, error, signIn, signOut, displayError, clearError, authProvider }; }
Sie werden die Implementierung dieses Kontexts in späteren Abschnitten abschließen.
Erstellen Sie eine Navigationsleiste für die App. Erstellen Sie eine neue Datei im
./src
Verzeichnis mit demNavBar.tsx
Namen, und fügen Sie den folgenden Code hinzu.import React from 'react'; import { NavLink as RouterNavLink } from 'react-router-dom'; import { Button, Collapse, Container, Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink, UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; import '@fortawesome/fontawesome-free/css/all.css'; interface NavBarProps { isAuthenticated: boolean; authButtonMethod: any; user: any; } interface NavBarState { isOpen: boolean; } function UserAvatar(props: any) { // If a user avatar is available, return an img tag with the pic if (props.user.avatar) { return <img src={props.user.avatar} alt="user" className="rounded-circle align-self-center mr-2" style={{ width: '32px' }}></img>; } // No avatar available, return a default icon return <i className="far fa-user-circle fa-lg rounded-circle align-self-center mr-2" style={{ width: '32px' }}></i>; } function AuthNavItem(props: NavBarProps) { // If authenticated, return a dropdown with the user's info and a // sign out button if (props.isAuthenticated) { return ( <UncontrolledDropdown> <DropdownToggle nav caret> <UserAvatar user={props.user} /> </DropdownToggle> <DropdownMenu right> <h5 className="dropdown-item-text mb-0">{props.user.displayName}</h5> <p className="dropdown-item-text text-muted mb-0">{props.user.email}</p> <DropdownItem divider /> <DropdownItem onClick={props.authButtonMethod}>Sign Out</DropdownItem> </DropdownMenu> </UncontrolledDropdown> ); } // Not authenticated, return a sign in link return ( <NavItem> <Button onClick={props.authButtonMethod} className="btn-link nav-link border-0" color="link">Sign In</Button> </NavItem> ); } export default class NavBar extends React.Component<NavBarProps, NavBarState> { constructor(props: NavBarProps) { super(props); this.toggle = this.toggle.bind(this); this.state = { isOpen: false }; } toggle() { this.setState({ isOpen: !this.state.isOpen }); } render() { // Only show calendar nav item if logged in let calendarLink = null; if (this.props.isAuthenticated) { calendarLink = ( <NavItem> <RouterNavLink to="/calendar" className="nav-link" exact>Calendar</RouterNavLink> </NavItem> ); } return ( <div> <Navbar color="dark" dark expand="md" fixed="top"> <Container> <NavbarBrand href="/">React Graph Tutorial</NavbarBrand> <NavbarToggler onClick={this.toggle} /> <Collapse isOpen={this.state.isOpen} navbar> <Nav className="mr-auto" navbar> <NavItem> <RouterNavLink to="/" className="nav-link" exact>Home</RouterNavLink> </NavItem> {calendarLink} </Nav> <Nav className="justify-content-end" navbar> <NavItem> <NavLink href="https://developer.microsoft.com/graph/docs/concepts/overview" target="_blank"> <i className="fas fa-external-link-alt mr-1"></i> Docs </NavLink> </NavItem> <AuthNavItem isAuthenticated={this.props.isAuthenticated} authButtonMethod={this.props.authButtonMethod} user={this.props.user} /> </Nav> </Collapse> </Container> </Navbar> </div> ); } }
Erstellen Sie eine Startseite für die App. Erstellen Sie eine neue Datei im
./src
Verzeichnis mit demWelcome.tsx
Namen, und fügen Sie den folgenden Code hinzu.import React from 'react'; import { Button, Jumbotron } from 'reactstrap'; interface WelcomeProps { isAuthenticated: boolean; authButtonMethod: any; user: any; } interface WelcomeState { isOpen: boolean; } function WelcomeContent(props: WelcomeProps) { // If authenticated, greet the user if (props.isAuthenticated) { return ( <div> <h4>Welcome {props.user.displayName}!</h4> <p>Use the navigation bar at the top of the page to get started.</p> </div> ); } // Not authenticated, present a sign in button return <Button color="primary" onClick={props.authButtonMethod}>Click here to sign in</Button>; } export default class Welcome extends React.Component<WelcomeProps, WelcomeState> { render() { return ( <Jumbotron> <h1>React Graph Tutorial</h1> <p className="lead"> This sample app shows how to use the Microsoft Graph API to access Outlook and OneDrive data from React </p> <WelcomeContent isAuthenticated={this.props.isAuthenticated} user={this.props.user} authButtonMethod={this.props.authButtonMethod} /> </Jumbotron> ); } }
Erstellen Sie eine Fehlermeldungsanzeige, um dem Benutzer Nachrichten anzuzeigen. Erstellen Sie eine neue Datei im
./src
Verzeichnis mit demErrorMessage.tsx
Namen, und fügen Sie den folgenden Code hinzu.import React from 'react'; import { Alert } from 'reactstrap'; interface ErrorMessageProps { debug: string; message: string; } export default class ErrorMessage extends React.Component<ErrorMessageProps> { render() { let debug = null; if (this.props.debug) { debug = <pre className="alert-pre border bg-light p-2"><code>{this.props.debug}</code></pre>; } return ( <Alert color="danger"> <p className="mb-3">{this.props.message}</p> {debug} </Alert> ); } }
Öffnen Sie die Datei
./src/index.css
, und ersetzen Sie ihren Inhalt durch Folgendes:body { padding-top: 4.5rem; } .alert-pre { word-wrap: break-word; word-break: break-all; white-space: pre-wrap; }
Öffnen
./src/App.tsx
Und ersetzen Sie den gesamten Inhalt durch Folgendes.import { BrowserRouter as Router, Route } from 'react-router-dom'; import { Container } from 'react-bootstrap'; import { MsalProvider } from '@azure/msal-react' import { IPublicClientApplication } from '@azure/msal-browser'; import ProvideAppContext from './AppContext'; import ErrorMessage from './ErrorMessage'; import NavBar from './NavBar'; import Welcome from './Welcome'; import 'bootstrap/dist/css/bootstrap.css'; export default function App() { return( <ProvideAppContext> <Router> <NavBar /> <Container> <ErrorMessage /> <Route exact path="/" render={(props) => <Welcome {...props} /> } /> </Container> </Router> </ProvideAppContext> ); }
Fügen Sie eine Bilddatei Ihrer Wahl namens no-profile-photo.png im Verzeichnis ./public/images hinzu. Dieses Bild wird als Foto des Benutzers verwendet, wenn der Benutzer kein Foto in Microsoft Graph hat.
Speichern Sie alle Änderungen, und starten Sie die App neu. Jetzt sollte die App ganz anders aussehen.
Registrieren der App im Portal
In dieser Übung erstellen Sie eine neue Azure AD-Webanwendungsregistrierung über das Azure Active Directory Admin Center.
Öffnen Sie einen Browser, und navigieren Sie zum Azure Active Directory Admin Center. Melden Sie sich mit einem persönlichen Konto (auch: Microsoft-Konto) oder einem Geschäfts- oder Schulkonto an.
Wählen Sie in der linken Navigationsleiste Azure Active Directory aus, und wählen Sie dann App-Registrierungen unter Verwalten aus.
Hinweis
Azure AD B2C-Benutzern werden möglicherweise nur App-Registrierungen (legacy) angezeigt. Gehen Sie in diesem Fall direkt zu https://aka.ms/appregistrations .
Wählen Sie Neue Registrierung aus. Legen Sie auf der Seite Anwendung registrieren die Werte wie folgt fest.
- Legen Sie Name auf
React Graph Tutorial
fest. - Legen Sie Unterstützte Kontotypen auf Konten in allen Organisationsverzeichnissen und persönliche Microsoft-Konten fest.
- Legen Sie unter Umleitungs-URI die erste Dropdownoption auf
Single-page application (SPA)
fest, und legen Sie den Wert aufhttp://localhost:3000
fest.
- Legen Sie Name auf
Wählen Sie Registrieren aus. Kopieren Sie auf der Seite React Graph Lernprogramm den Wert der Anwendungs-ID (Client-ID), und speichern Sie sie, sie benötigen Sie im nächsten Schritt.
Hinzufügen der Azure AD-Authentifizierung
In dieser Übung erweitern Sie die Anwendung aus der vorherigen Übung, um die Authentifizierung mit Azure AD zu unterstützen. Dies ist erforderlich, um das erforderliche OAuth-Zugriffstoken abzurufen, um die Microsoft Graph aufzurufen. In diesem Schritt integrieren Sie die Microsoft-Authentifizierungsbibliotheksbibliothek in die Anwendung.
Erstellen Sie eine neue Datei im Verzeichnis ./src mit dem Namen "Config.ts", und fügen Sie den folgenden Code hinzu.
export const config = { appId: 'YOUR_APP_ID_HERE', redirectUri: 'http://localhost:3000', scopes: [ 'user.read', 'mailboxsettings.read', 'calendars.readwrite' ] };
Ersetzen Sie
YOUR_APP_ID_HERE
dies durch die Anwendungs-ID aus dem Anwendungsregistrierungsportal.Wichtig
Wenn Sie die Quellcodeverwaltung wie Git verwenden, wäre jetzt ein guter Zeitpunkt, um die
Config.ts
Datei aus der Quellcodeverwaltung auszuschließen, um zu vermeiden, dass versehentlich Ihre App-ID offengelegt wird.
Implementieren der Anmeldung
In diesem Abschnitt implementieren Sie einen Authentifizierungsanbieter, eine Anmeldung und eine Abmeldung.
Öffnen Sie ./src/index.tsx, und fügen Sie die folgenden
import
Anweisungen am Anfang der Datei hinzu.import { PublicClientApplication, EventType, EventMessage, AuthenticationResult } from '@azure/msal-browser'; import config from './Config';
Fügen Sie den folgenden Code vor der
ReactDOM.render
Zeile hinzu.Dieser Code erstellt eine Instanz des Objekts der MSAL-Bibliothek,
PublicClientApplication
sucht nach zwischengespeicherten Konten und registriert einen Rückruf, um das aktive Konto nach einer erfolgreichen Anmeldung festzulegen.Aktualisieren Sie das
App
Element imReactDOM.render
Aufruf, um es in einer Eigenschaft mit dem Namen zumsalInstance
pca
übergeben.Öffnen Sie ./src/App.tsx, und fügen Sie den folgenden Code nach der letzten
import
Anweisung hinzu.Ersetzen Sie die vorhandene
App
-Funktion durch Folgendes.export default function App({ pca }: AppProps) { return( <MsalProvider instance={ pca }> <ProvideAppContext> <Router> <div> <NavBar /> <Container> <ErrorMessage /> <Route exact path="/" render={(props) => <Welcome {...props} /> } /> </Container> </div> </Router> </ProvideAppContext> </MsalProvider> ); }
Dadurch werden alle anderen Elemente mit dem Element umbrochen, sodass der
MsalProvider
Authentifizierungsstatus und der Tokenerwerb verfügbar sind.Öffnen Sie "./src/AppContext.tsx", und fügen Sie die folgende
import
Anweisung am Anfang der Datei hinzu.import config from './Config';
Fügen Sie oben in der Funktion die folgende Zeile
useProvideAppContext
hinzu.const msal = useMsal();
Ersetzen Sie die
const authProvider = undefined;
Zeile durch Folgendes.Ersetzen Sie die vorhandene
signIn
-Funktion durch Folgendes.const signIn = async () => { const result = await msal.instance.loginPopup({ scopes: config.scopes, prompt: 'select_account' }); // TEMPORARY: Show the access token displayError('Access token retrieved', result.accessToken); };
Speichern Sie Ihre Änderungen, und aktualisieren Sie den Browser. Klicken Sie auf die Anmeldeschaltfläche, und es sollte ein Popupfenster angezeigt werden, das geladen
https://login.microsoftonline.com
wird. Melden Sie sich mit Ihrem Microsoft-Konto an, und stimmen Sie den angeforderten Berechtigungen zu. Die App-Seite sollte mit dem Token aktualisiert werden.
Benutzerdetails abrufen
In diesem Abschnitt ändern Sie die signIn
Funktion, um die Details des Benutzers von Microsoft Graph abzurufen.
Erstellen Sie eine neue Datei im Verzeichnis ./src mit dem Namen GraphService.ts, und fügen Sie den folgenden Code hinzu.
Dadurch wird die
getUser
Funktion implementiert, die den Microsoft Graph-Client mit dem bereitgestellten initialisiertAuthProvider
und das Profil des Benutzers abruft.Öffnen Sie "./src/AppContext.tsx", und fügen Sie die folgende
import
Anweisung am Anfang der Datei hinzu.import { getUser } from './GraphService';
Ersetzen Sie die vorhandene
signIn
-Funktion durch den folgenden Code.Ersetzen Sie die vorhandene
signOut
-Funktion durch Folgendes.Fügen Sie den folgenden
useEffect
Aufruf inuseProvideAppContext
.Speichern Sie Ihre Änderungen, und starten Sie die App. Nach der Anmeldung sollten Sie wieder auf der Startseite enden, aber die Benutzeroberfläche sollte sich ändern, um anzugeben, dass Sie angemeldet sind.
Klicken Sie auf den Benutzer-Avatar in der oberen rechten Ecke, um auf den Abmeldelink zuzugreifen. Wenn Sie auf Abmelden klicken, wird die Sitzung zurückgesetzt und Sie kehren zur Startseite zurück.
Speichern und Aktualisieren von Token
An diesem Punkt verfügt Ihre Anwendung über ein Zugriffstoken, das in der Authorization
Kopfzeile von API-Aufrufen gesendet wird. Dies ist das Token, mit dem die App im Namen des Benutzers auf die Microsoft-Graph zugreifen kann.
Dieses Token ist jedoch nur kurzzeitig verfügbar. Das Token läuft eine Stunde nach der Ausstellung ab. An dieser Stelle kommt das Aktualisierungstoken ins Spiel. Anhand des Aktualisierungstoken ist die App in der Lage, ein neues Zugriffstoken anzufordern, ohne dass der Benutzer sich erneut anmelden muss.
Da die App die MSAL-Bibliothek verwendet, müssen Sie keine Tokenspeicher- oder Aktualisierungslogik implementieren. Das PublicClientApplication
Token wird in der Browsersitzung zwischengespeichert. Die acquireTokenSilent
Methode überprüft zuerst das zwischengespeicherte Token und gibt es zurück, wenn es nicht abgelaufen ist. Wenn es abgelaufen ist, wird das zwischengespeicherte Aktualisierungstoken verwendet, um ein neues abzurufen. Sie werden diese Methode im folgenden Modul weiter verwenden.
Abrufen einer Kalenderansicht
In dieser Übung integrieren Sie die Microsoft Graph in die Anwendung. Für diese Anwendung verwenden Sie die Microsoft-Graph-Clientbibliothek, um Aufrufe an Microsoft Graph zu tätigen.
Abrufen von Kalenderereignissen von Outlook
Öffnen Sie ./src/GraphService.ts , und fügen Sie die folgende Funktion hinzu.
export async function getUserWeekCalendar(accessToken: string, timeZone: string, startDate: Moment): Promise<Event[]> { const client = getAuthenticatedClient(accessToken); // Generate startDateTime and endDateTime query params // to display a 7-day window var startDateTime = startDate.format(); var endDateTime = moment(startDate).add(7, 'day').format(); // GET /me/calendarview?startDateTime=''&endDateTime='' // &$select=subject,organizer,start,end // &$orderby=start/dateTime // &$top=50 var response: PageCollection = await client .api('/me/calendarview') .header('Prefer', `outlook.timezone="${timeZone}"`) .query({ startDateTime: startDateTime, endDateTime: endDateTime }) .select('subject,organizer,start,end') .orderby('start/dateTime') .top(25) .get(); if (response["@odata.nextLink"]) { // Presence of the nextLink property indicates more results are available // Use a page iterator to get all results var events: Event[] = []; // Must include the time zone header in page // requests too var options: GraphRequestOptions = { headers: { 'Prefer': `outlook.timezone="${timeZone}"` } }; var pageIterator = new PageIterator(client, response, (event) => { events.push(event); return true; }, options); await pageIterator.iterate(); return events; } else { return response.value; } }
Überlegen Sie sich, was dieser Code macht.
- Die URL, die aufgerufen wird, lautet
/me/calendarview
. - Die
header
Methode fügt der Anforderung denPrefer: outlook.timezone=""
Header hinzu, wodurch sich die Uhrzeiten in der Antwort in der bevorzugten Zeitzone des Benutzers befinden. - Die
query
Methode fügt diestartDateTime
Parameter hinzu undendDateTime
definiert das Zeitfenster für die Kalenderansicht. - Die
select
Methode beschränkt die für jedes Ereignis zurückgegebenen Felder auf die Felder, die tatsächlich von der Ansicht verwendet werden. - Die
orderby
Methode sortiert die Ergebnisse nach dem Datum und der Uhrzeit, zu der sie erstellt wurden, wobei das letzte Element zuerst ist. - Die
top
Methode beschränkt die Ergebnisse in einer einzelnen Seite auf 25 Ereignisse. - Wenn die Antwort einen
@odata.nextLink
Wert enthält, der angibt, dass mehr Ergebnisse verfügbar sind, wird einPageIterator
Objekt verwendet, um die Auflistung zu durchlaufen , um alle Ergebnisse abzurufen.
- Die URL, die aufgerufen wird, lautet
Erstellen Sie eine React Komponente, um die Ergebnisse des Aufrufs anzuzeigen. Erstellen Sie eine neue Datei im Verzeichnis ./src mit dem Namen Calendar.tsx , und fügen Sie den folgenden Code hinzu.
import { useEffect, useState } from 'react'; import { NavLink as RouterNavLink, RouteComponentProps } from 'react-router-dom'; import { Table } from 'react-bootstrap'; import { findIana } from "windows-iana"; import { Event } from 'microsoft-graph'; import { getUserWeekCalendar } from './GraphService'; import { useAppContext } from './AppContext'; import { AuthenticatedTemplate } from '@azure/msal-react'; import { add, format, getDay, parseISO } from 'date-fns'; import { endOfWeek, startOfWeek } from 'date-fns/esm'; export default function Calendar(props: RouteComponentProps) { const app = useAppContext(); const [events, setEvents] = useState<Event[]>(); useEffect(() => { const loadEvents = async() => { if (app.user && !events) { try { const ianaTimeZones = findIana(app.user?.timeZone!); const events = await getUserWeekCalendar(app.authProvider!, ianaTimeZones[0].valueOf()); setEvents(events); } catch (err) { app.displayError!(err.message); } } }; loadEvents(); }); return ( <AuthenticatedTemplate> <pre><code>{JSON.stringify(events, null, 2)}</code></pre> </AuthenticatedTemplate> ); }
Damit wird derzeit nur das Array von Ereignissen in JSON auf der Seite gerendert.
Fügen Sie diese neue Komponente zur App hinzu. Öffnen
./src/App.tsx
Sie die folgendeimport
Anweisung, und fügen Sie sie am Anfang der Datei hinzu.import Calendar from './Calendar';
Fügen Sie die folgende Komponente direkt hinter der vorhandenen
<Route>
hinzu.<Route exact path="/calendar" render={(props) => <Calendar {...props} /> } />
Speichern Sie die Änderungen, und starten Sie die App neu. Melden Sie sich an, und klicken Sie auf den Kalenderlink in der Navigationsleiste. Wenn alles funktioniert, sollte ein JSON-Abbild von Ereignissen im Kalender des Benutzers angezeigt werden.
Anzeigen der Ergebnisse
Jetzt können Sie die Calendar
Komponente aktualisieren, um die Ereignisse auf benutzerfreundlichere Weise anzuzeigen.
Erstellen Sie eine neue Datei im Verzeichnis mit dem
./src
NamenCalendar.css
, und fügen Sie den folgenden Code hinzu..calendar-view-date-cell { width: 150px; } .calendar-view-date { width: 40px; font-size: 36px; line-height: 36px; margin-right: 10px; } .calendar-view-month { font-size: 0.75em; } .calendar-view-timespan { width: 200px; } .calendar-view-subject { font-size: 1.25em; } .calendar-view-organizer { font-size: .75em; }
Erstellen Sie eine React Komponente, um Ereignisse an einem einzelnen Tag als Tabellenzeilen zu rendern. Erstellen Sie eine neue Datei im Verzeichnis mit dem
./src
NamenCalendarDayRow.tsx
, und fügen Sie den folgenden Code hinzu.import React from 'react'; import moment, { Moment } from 'moment'; import { Event } from 'microsoft-graph'; interface CalendarDayRowProps { date: Moment | undefined; timeFormat: string; events: Event[]; } interface FormatMap { [key: string] : string; } // moment.js format strings are slightly // different than the ones returned by Graph const formatMap: FormatMap = { "h:mm tt": "h:mm A", "hh:mm tt": "hh:mm A" }; // Helper function to format Graph date/time in the user's // preferred format function formatDateTime(dateTime: string | undefined, format: string) { if (dateTime !== undefined) { return moment(dateTime).format(formatMap[format] || format); } } export default class CalendarDayRow extends React.Component<CalendarDayRowProps> { render() { var today = moment(); var rowClass = today.day() === this.props.date?.day() ? 'table-warning' : ''; var timeFormat = this.props.timeFormat; var dateCell = ( <td className='calendar-view-date-cell' rowSpan={this.props.events.length <= 0 ? 1 : this.props.events.length}> <div className='calendar-view-date float-left text-right'>{this.props.date?.format('DD')}</div> <div className='calendar-view-day'>{this.props.date?.format('dddd')}</div> <div className='calendar-view-month text-muted'>{this.props.date?.format('MMMM, YYYY')}</div> </td> ); if (this.props.events.length <= 0) { // Render an empty row for the day return ( <tr className={rowClass}> {dateCell} <td></td> <td></td> </tr> ); } return ( <React.Fragment> {this.props.events.map( function(event: Event, index: Number) { return ( <tr className={rowClass} key={event.id}> { index === 0 && dateCell } <td className="calendar-view-timespan"> <div>{formatDateTime(event.start?.dateTime, timeFormat)} - {formatDateTime(event.end?.dateTime, timeFormat)}</div> </td> <td> <div className="calendar-view-subject">{event.subject}</div> <div className="calendar-view-organizer">{event.organizer?.emailAddress?.name}</div> </td> </tr> ) } )} </React.Fragment> ) } }
Add the following
import
statements to the top of Calendar.tsx.import CalendarDayRow from './CalendarDayRow'; import './Calendar.css';
Ersetzen Sie die vorhandene
return
Anweisung durch den folgenden Code.Dadurch werden die Ereignisse in die jeweiligen Tage aufgeteilt und ein Tabellenabschnitt für jeden Tag gerendert.
Speichern Sie die Änderungen, und starten Sie die App neu. Klicken Sie auf den Kalenderlink , und die App sollte nun eine Tabelle mit Ereignissen rendern.
Erstellen eines neuen Ereignisses
In diesem Abschnitt fügen Sie die Möglichkeit hinzu, Ereignisse im Kalender des Benutzers zu erstellen.
Hinzufügen einer Methode zu GraphService
Öffnen Sie ./src/GraphService.ts , und fügen Sie die folgende Funktion hinzu, um ein neues Ereignis zu erstellen.
export async function createEvent(accessToken: string, newEvent: Event): Promise<Event> { const client = getAuthenticatedClient(accessToken); // POST /me/events // JSON representation of the new event is sent in the // request body return await client .api('/me/events') .post(newEvent); }
Erstellen eines neuen Ereignisformulars
Erstellen Sie eine neue Datei im Verzeichnis "./src " mit dem Namen "NewEvent.tsx" , und fügen Sie den folgenden Code hinzu.
import React from 'react'; import { NavLink as RouterNavLink, Redirect } from 'react-router-dom'; import { Button, Col, Form, FormGroup, Label, Input, Row } from 'reactstrap'; import { Attendee, Event } from 'microsoft-graph'; import { config } from './Config'; import withAuthProvider, { AuthComponentProps } from './AuthProvider'; import { createEvent } from './GraphService'; interface NewEventState { subject: string; attendees: string; start: string; end: string; body: string; disableCreate: boolean; redirect: boolean; } class NewEvent extends React.Component<AuthComponentProps, NewEventState> { constructor(props: any) { super(props); this.state = { subject: '', attendees: '', start: '', end: '', body: '', disableCreate: true, redirect: false } this.handleUpdate = this.handleUpdate.bind(this); this.isFormDisabled = this.isFormDisabled.bind(this); this.createEvent = this.createEvent.bind(this); } // Called whenever an input is changed handleUpdate(event: React.ChangeEvent<HTMLInputElement>) { // Set the state value that maps to the input var newState: any = { [event.target.name]: event.target.value }; this.setState(newState); } // Determines if form is ready to submit // Requires a subject, start, and end isFormDisabled(): boolean { return this.state.subject.length === 0 || this.state.start.length === 0 || this.state.end.length === 0; } // Creates the event when user clicks Create async createEvent() { // Get the value of attendees and split into an array var attendeeEmails = this.state.attendees.split(';'); var attendees: Attendee[] = []; // Create an Attendee object for each email address attendeeEmails.forEach((email) => { if (email.length > 0) { attendees.push({ emailAddress: { address: email } }); } }); // Create the Event object var newEvent: Event = { subject: this.state.subject, // Only add if there are attendees attendees: attendees.length > 0 ? attendees : undefined, // Specify the user's time zone so // the start and end are set correctly start: { dateTime: this.state.start, timeZone: this.props.user.timeZone }, end: { dateTime: this.state.end, timeZone: this.props.user.timeZone }, // Only add if a body was given body: this.state.body.length > 0 ? { contentType: "text", content: this.state.body } : undefined } try { // Get the user's access token var accessToken = await this.props.getAccessToken(config.scopes); // Create the event await createEvent(accessToken, newEvent); // Redirect to the calendar view this.setState({ redirect: true }); } catch (err) { this.props.setError('ERROR', JSON.stringify(err)); } } render() { if (this.state.redirect) { return <Redirect to="/calendar" /> } return ( <Form> <FormGroup> <Label for="subject">Subject</Label> <Input type="text" name="subject" id="subject" value={this.state.subject} onChange={this.handleUpdate} /> </FormGroup> <FormGroup> <Label for="attendees">Attendees</Label> <Input type="text" name="attendees" id="attendees" placeholder="Enter a list of email addresses, seperated by a semi-colon" value={this.state.attendees} onChange={this.handleUpdate} /> </FormGroup> <Row form> <Col> <FormGroup> <Label for="start">Start</Label> <Input type="datetime-local" name="start" id="start" value={this.state.start} onChange={this.handleUpdate} /> </FormGroup> </Col> <Col> <FormGroup> <Label for="end">End</Label> <Input type="datetime-local" name="end" id="end" value={this.state.end} onChange={this.handleUpdate} /> </FormGroup> </Col> </Row> <FormGroup> <Label for="body">Body</Label> <Input type="textarea" name="body" id="body" value={this.state.body} onChange={this.handleUpdate} /> </FormGroup> <Button color="primary" className="mr-2" disabled={this.isFormDisabled()} onClick={this.createEvent}>Create</Button> <RouterNavLink to="/calendar" className="btn btn-secondary" exact>Cancel</RouterNavLink> </Form> ) } } export default withAuthProvider(NewEvent);
Öffnen Sie ./src/App.tsx , und fügen Sie die folgende
import
Anweisung am Anfang der Datei hinzu.import NewEvent from './NewEvent';
Fügen Sie dem neuen Ereignisformular eine neue Route hinzu. Fügen Sie den folgenden Code direkt hinter den anderen
Route
Elementen hinzu.<Route exact path="/newevent" render={(props) => <NewEvent {...props} /> } />
Die vollständige
return
Anweisung sollte nun wie folgt aussehen.Aktualisieren Sie die App, und navigieren Sie zur Kalenderansicht. Klicken Sie auf die Schaltfläche "Neues Ereignis ". Füllen Sie die Felder aus, und klicken Sie auf "Erstellen".
Herzlichen Glückwunsch!
Sie haben das Lernprogramm React Microsoft Graph abgeschlossen. Nachdem Sie nun über eine funktionierende App verfügen, die Microsoft Graph aufruft, können Sie experimentieren und neue Features hinzufügen. Besuchen Sie die Übersicht über Microsoft Graph, um alle Daten anzuzeigen, auf die Sie mit Microsoft Graph zugreifen können.
Feedback
Bitte geben Sie Feedback zu diesem Lernprogramm im GitHub Repository.
Liegt ein Problem mit diesem Abschnitt vor? Wenn ja, senden Sie uns Feedback, damit wir den Abschnitt verbessern können.