Aktualisieren der App zum Erstellen und Auflisten von SharePoint Embedded-Containern
In dieser Übung aktualisieren Sie das vorhandene Projekt, um SharePoint Embedded-Container zu erstellen und abzurufen.
Hinzufügen von Anmeldefunktionen zum Front-End von React SPA
Beginnen wir mit dem Hinzufügen von Unterstützung für die Benutzeranmeldung beim React SPA-Front-End-Projekt. Dies umfasst das Hinzufügen von Konfigurationscode für die Microsoft Authentication Library (MSAL) und das Konfigurieren des Microsoft Graph-Toolkits mit den erforderlichen Anmeldedetails.
Einrichten des Authentifizierungsanbieters
Suchen und öffnen Sie die Datei ./src/index.tsx .
Fügen Sie die folgenden Importe nach den vorhandenen Importen hinzu:
import { Providers } from "@microsoft/mgt-element";
import { Msal2Provider } from "@microsoft/mgt-msal2-provider";
import * as Constants from "./common/constants"
import * as Scopes from "./common/scopes";
Fügen Sie abschließend den folgenden Code vor dem React-Renderingcode hinzu, um einen globalen MSAL-Anbieter für das Microsoft Graph-Toolkit zu konfigurieren:
Providers.globalProvider = new Msal2Provider({
clientId: Constants.CLIENT_ENTRA_APP_CLIENT_ID,
authority: Constants.CLIENT_ENTRA_APP_AUTHORITY,
scopes: [
...Scopes.GRAPH_OPENID_CONNECT_BASIC,
Scopes.GRAPH_USER_READ_ALL,
Scopes.GRAPH_FILES_READ_WRITE_ALL,
Scopes.GRAPH_SITES_READ_ALL,
Scopes.SPEMBEDDED_FILESTORAGECONTAINER_SELECTED
]
});
Aktualisieren der App-Startseite zum Verarbeiten des An- und Abmeldevorgangs
Suchen und öffnen Sie die Datei ./src/App.tsx . Entfernen Sie den Import für die logo.svg
Datei, und fügen Sie dann die verbleibenden Importe hinzu, und aktualisieren Sie sie, um den folgenden Code widerzuspiegeln:
import React, {
useState, useEffect
} from "react";
import {
Providers,
ProviderState
} from "@microsoft/mgt-element";
import { Login } from "@microsoft/mgt-react";
import {
FluentProvider,
Text,
webLightTheme
} from "@fluentui/react-components"
import './App.css';
import {
InteractionRequiredAuthError,
PublicClientApplication
} from "@azure/msal-browser";
import * as Scopes from "./common/scopes";
import * as Constants from "./common/constants";
Fügen Sie nach den Importanweisungen den folgenden benutzerdefinierten React-Hook hinzu, um den Anmeldestatus des aktuellen Benutzers abzurufen:
function useIsSignedIn() {
const [isSignedIn, setIsSignedIn] = useState(false);
useEffect(() => {
const updateState = async () => {
const provider = Providers.globalProvider;
setIsSignedIn(provider && provider.state === ProviderState.SignedIn);
};
Providers.onProviderUpdated(updateState);
updateState();
return () => {
Providers.removeProviderUpdatedListener(updateState);
}
}, []);
return isSignedIn;
}
Aktualisieren Sie nun den App
, indem Sie den folgenden Code nach der Deklaration hinzufügen:
const isSignedIn = useIsSignedIn();
const promptForContainerConsent = async (event: CustomEvent<undefined>): Promise<void> => {
const containerScopes = {
scopes: [Scopes.SPEMBEDDED_FILESTORAGECONTAINER_SELECTED],
redirectUri: `${window.location.protocol}://${window.location.hostname}${(window.location.port === '80' || window.location.port === '443') ? '' : ':' + window.location.port}`
};
const msalInstance = new PublicClientApplication({
auth: {
clientId: Constants.CLIENT_ENTRA_APP_CLIENT_ID,
authority: Constants.CLIENT_ENTRA_APP_AUTHORITY,
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false,
},
});
msalInstance.acquireTokenSilent(containerScopes)
.then(response => {
console.log('tokenResponse', JSON.stringify(response));
})
.catch(async (error) => {
if (error instanceof InteractionRequiredAuthError) {
return msalInstance.acquireTokenPopup(containerScopes);
}
});
}
Dieser Code ruft zuerst den aktuellen Anmeldestatus des Benutzers ab und konfiguriert und ruft dann ein Zugriffstoken ab, sobald der Benutzer eine Schaltfläche im Rendering auswählt.
Aktualisieren Sie abschließend das Rendering der Komponente, indem Sie die -Anweisung der Komponente return()
durch Folgendes ersetzen:
return (
<FluentProvider theme={webLightTheme}>
<div className="App">
<Text size={900} weight='bold'>Sample SPA SharePoint Embedded App</Text>
<Login loginCompleted={promptForContainerConsent} />
<div>
</div>
</div>
</FluentProvider>
);
Testen der Authentifizierung für die React-App
Testen Sie nun die clientseitige React-App, um sicherzustellen, dass die Authentifizierung funktioniert.
Führen Sie über die Befehlszeile im Stammordner des Projekts den folgenden Befehl aus:
npm run start
Das Skript erstellt die serverseitigen & clientseitigen Projekten, startet sie und startet einen Browser für das clientseitige Projekt:
Wählen Sie die Schaltfläche Anmelden aus, und melden Sie sich mit dem Geschäfts-, Schul- und Unikonto mit Administratorzugriff auf Ihren Microsoft 365-Mandanten an.
Nachdem Sie sich erfolgreich angemeldet haben, werden Sie zurück zu Ihrer React-App weitergeleitet und zeigen den Namen und die E-Mail-Adresse des angemeldeten Benutzers an:
Beenden Sie den Server durch Drücken von STRG + C in der Konsole.
Hinzufügen der Möglichkeit zum Auflisten und Auswählen von Containern
Nachdem das grundlegende Projekt eingerichtet und für die Unterstützung der Benutzerauthentifizierung konfiguriert ist, fügen wir jetzt Unterstützung hinzu, um Container in der Partition Ihres Mandanten aufzulisten und auszuwählen.
Die Containerverwaltung ist ein privilegierter Vorgang, der ein Zugriffstoken erfordert, das serverseitig abgerufen werden muss. Zunächst erstellen wir die serverseitigen API-Teile zur Unterstützung der React-App.
Hinzufügen einer Hilfsmethode zum Abrufen eines OBO-Tokens zum Aufrufen von Microsoft Graph
Wir benötigen zunächst eine Hilfsprogrammdatei, um ein Token mithilfe des OAuth2-On-Behalf-Of-Flusses mit unseren vorhandenen Anmeldeinformationen abzurufen.
Erstellen Sie eine neue Datei ./server/auth.ts , und fügen Sie ihr den folgenden Code hinzu:
import { ConfidentialClientApplication } from "@azure/msal-node";
require('isomorphic-fetch');
import * as MSGraph from '@microsoft/microsoft-graph-client';
import * as Scopes from './common/scopes';
export const getGraphToken = async (confidentialClient: ConfidentialClientApplication, token: string): Promise<[boolean, string | any]> => {
try {
const graphTokenRequest = {
oboAssertion: token,
scopes: [
Scopes.GRAPH_SITES_READ_ALL,
Scopes.SPEMBEDDED_FILESTORAGECONTAINER_SELECTED
]
};
const oboGraphToken = (await confidentialClient.acquireTokenOnBehalfOf(graphTokenRequest))!.accessToken;
return [true, oboGraphToken];
} catch (error: any) {
const errorResult = {
status: 500,
body: JSON.stringify({
message: `Unable to generate Microsoft Graph OBO token: ${error.message}`,
providedToken: token
})
};
return [false, errorResult];
}
}
Dabei wird eine konfigurierte ConfidentialClientApplication und das ID-Token des Benutzers verwendet und die MSAL-Bibliothek verwendet, um ein neues Token anzufordern, das wir zum Aufrufen von Microsoft Graph verwenden können.
Hinzufügen der Containerverwaltung zum serverseitigen API-Projekt
Nun erstellen wir den Handler, um eine Liste der Container mit Microsoft Graph abzurufen, die an unsere React-App zurückgegeben werden sollen. Erstellen Sie eine neue Datei ./server/listContainers.ts , und fügen Sie ihr die folgenden Importe hinzu:
import {
Request,
Response
} from "restify";
import * as MSAL from "@azure/msal-node";
require('isomorphic-fetch');
import * as MSGraph from '@microsoft/microsoft-graph-client';
import { getGraphToken } from "./auth";
Fügen Sie als Nächstes den folgenden Code hinzu, um eine Instanz einer MSAL ConfidentialClientApplication zu erstellen, die zum Abrufen des OBO-Zugriffstokens verwendet wird:
const msalConfig: MSAL.Configuration = {
auth: {
clientId: process.env['API_ENTRA_APP_CLIENT_ID']!,
authority: process.env['API_ENTRA_APP_AUTHORITY']!,
clientSecret: process.env['API_ENTRA_APP_CLIENT_SECRET']!
},
system: {
loggerOptions: {
loggerCallback(loglevel: any, message: any, containsPii: any) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: MSAL.LogLevel.Verbose,
}
}
};
const confidentialClient = new MSAL.ConfidentialClientApplication(msalConfig);
Erstellen und exportieren Sie eine neue Funktion, die folgende Aktionen ausführen soll:
- Überprüfen Sie, ob die Anforderung einen
Authorization
Header mit einem Zugriffstoken enthält. - Verwenden Sie , die dieses Token und verwenden,
ConfidentialClientApplication
um ein OBO-Token abzurufen, das wir zum Aufrufen von Microsoft Graph verwenden können. - Verwenden Sie das OBO-Token, um einen neuen
AuthenticationProvider
Client zu erstellen, den wir zum Aufrufen von Microsoft Graph verwenden.
export const listContainers = async (req: Request, res: Response) => {
if (!req.headers.authorization) {
res.send(401, { message: 'No access token provided.' });
return;
}
const [bearer, token] = (req.headers.authorization || '').split(' ');
const [graphSuccess, oboGraphToken] = await getGraphToken(confidentialClient, token);
if (!graphSuccess) {
res.send(200, oboGraphToken);
return;
}
const authProvider = (callback: MSGraph.AuthProviderCallback) => {
callback(null, oboGraphToken);
};
}
Der letzte Schritt besteht darin, den Microsoft Graph-Client zu erstellen und alle Container anzufordern, die einen bestimmten ContainerTypeId
Satz aufweisen. Fügen Sie die folgende Code-Unmittelbarkeit vor der schließende Klammer der Funktion hinzu:
try {
const graphClient = MSGraph.Client.init({
authProvider: authProvider,
defaultVersion: 'beta'
});
const graphResponse = await graphClient.api(`storage/fileStorage/containers?$filter=containerTypeId eq ${process.env["CONTAINER_TYPE_ID"]}`).get();
res.send(200, graphResponse);
return;
} catch (error: any) {
res.send(500, { message: `Unable to list containers: ${error.message}` });
return;
}
Fügen Sie diesen neuen Endpunkt zu unserem Restify-Server hinzu. Suchen und öffnen Sie die Datei ./server/index.ts , fügen Sie eine einzelne Import-Anweisung am Ende der vorhandenen Importe hinzu, und fügen Sie einen Listener für HTTP GET-Anforderungen an den /api/listContainers
Endpunkt hinzu:
import { listContainers } from "./listContainers";
...
server.get('/api/listContainers', async (req, res, next) => {
try {
const response = await listContainers(req, res);
res.send(200, response)
} catch (error: any) {
res.send(500, { message: `Error in API server: ${error.message}` });
}
next();
});
Aktualisieren des React-Projekts, um unsere Container anzuzeigen
Mit der serverseitigen API-Einrichtung können wir unser React-Projekt aktualisieren, um Benutzern eine Schnittstelle zum Auswählen eines vorhandenen Containers oder zum Erstellen eines neuen Containers bereitzustellen.
Erstellen Sie zunächst die neue Schnittstelle ./src/common/IContainer.ts mit dem folgenden Inhalt, der das Objekt darstellt, das wir von Microsoft Graph-Aufrufen senden und empfangen:
export interface IContainer {
id: string;
displayName: string;
containerTypeId: string;
createdDateTime: string;
}
Erstellen Sie einen neuen Dienst, der verwendet wird, um unseren API-Endpunkt aufzurufen oder direkte Aufrufe von der React-App an Microsoft Graph zu senden. Erstellen Sie eine neue Datei ./src/services/spembedded.ts , und fügen Sie den folgenden Code hinzu:
import { Providers, ProviderState } from '@microsoft/mgt-element';
import * as Msal from '@azure/msal-browser';
import * as Constants from './../common/constants';
import * as Scopes from './../common/scopes';
import { IContainer } from './../common/IContainer';
export default class SpEmbedded {
}
Fügen Sie als Nächstes eine Hilfsfunktion hinzu, um ein Zugriffstoken abzurufen, das wir zum Aufrufen von Microsoft Graph verwenden können. Dadurch wird eine MSAL PublicClientApplication
erstellt, die zum Übermitteln unserer serverseitigen API verwendet wird. Fügen Sie der SharePoint Embedded-Klasse die folgende Funktion hinzu:
async getApiAccessToken() {
const msalConfig: Msal.Configuration = {
auth: {
clientId: Constants.CLIENT_ENTRA_APP_CLIENT_ID,
authority: Constants.CLIENT_ENTRA_APP_AUTHORITY,
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false
}
};
const scopes: Msal.SilentRequest = {
scopes: [`api://${Constants.CLIENT_ENTRA_APP_CLIENT_ID}/${Scopes.SPEMBEDDED_CONTAINER_MANAGE}`],
prompt: 'select_account',
redirectUri: `${window.location.protocol}//${window.location.hostname}${(window.location.port === '80' || window.location.port === '443') ? '' : ':' + window.location.port}`
};
const publicClientApplication = new Msal.PublicClientApplication(msalConfig);
await publicClientApplication.initialize();
let tokenResponse;
try {
tokenResponse = await publicClientApplication.acquireTokenSilent(scopes);
return tokenResponse.accessToken;
} catch (error) {
if (error instanceof Msal.InteractionRequiredAuthError) {
tokenResponse = await publicClientApplication.acquireTokenPopup(scopes);
return tokenResponse.accessToken;
}
console.log(error)
return null;
}
};
Fügen Sie die folgende listContainers()
Methode hinzu, die unsere serverseitige API aufruft, um eine Liste aller Container abzurufen. Dadurch wird das Von der Hilfsprogrammmethode zurückgegebene Zugriffstoken abgerufen und in Aufrufe der serverseitigen API eingeschlossen. Denken Sie daran, dass dieses Zugriffstoken verwendet wird, um eine MSAL ConfidentialClientApplication
zu erstellen, um ein OBO-Token zum Aufrufen von Microsoft Graph abzurufen. Dieses OBO-Token verfügt über mehr Berechtigungen, die nur über einen serverseitigen Aufruf abgerufen werden können:
async listContainers(): Promise<IContainer[] | undefined> {
const api_endpoint = `${Constants.API_SERVER_URL}/api/listContainers`;
if (Providers.globalProvider.state === ProviderState.SignedIn) {
const token = await this.getApiAccessToken();
const containerRequestHeaders = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
const containerRequestOptions = {
method: 'GET',
headers: containerRequestHeaders
};
const response = await fetch(api_endpoint, containerRequestOptions);
if (response.ok) {
const containerResponse = await response.json();
return (containerResponse.value)
? (containerResponse.value) as IContainer[]
: undefined;
} else {
console.error(`Unable to list Containers: ${JSON.stringify(response)}`);
return undefined;
}
}
};
Erstellen Sie nun eine neue React-Komponente, die alle Containeraufgaben und die Benutzeroberfläche verarbeitet. Erstellen Sie die neue Datei ./src/components/containers.tsx, und fügen Sie ihr den folgenden Code hinzu:
import React, { useEffect, useState } from 'react';
import {
Button,
Dialog, DialogActions, DialogContent, DialogSurface, DialogBody, DialogTitle, DialogTrigger,
Dropdown, Option,
Input, InputProps, InputOnChangeData,
Label,
Spinner,
makeStyles, shorthands, useId
} from '@fluentui/react-components';
import type {
OptionOnSelectData,
SelectionEvents
} from '@fluentui/react-combobox'
import { IContainer } from "./../common/IContainer";
import SpEmbedded from '../services/spembedded';
const spe = new SpEmbedded();
const useStyles = makeStyles({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
...shorthands.padding('25px'),
},
containerSelector: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
rowGap: '10px',
...shorthands.padding('25px'),
},
containerSelectorControls: {
width: '400px',
},
dialogContent: {
display: 'flex',
flexDirection: 'column',
rowGap: '10px',
marginBottom: '25px'
}
});
export const Containers = (props: any) => {
// BOOKMARK 1 - constants & hooks
// BOOKMARK 2 - handlers go here
// BOOKMARK 3 - component rendering
return (
);
}
export default Containers;
Hinweis
Beachten Sie die // BOOKMARK #
Kommentare in der Komponente. Diese stellen sicher, dass Sie Code an den richtigen Stellen hinzufügen.
Der erste Schritt besteht darin, eine Liste der Container abzurufen. Fügen Sie zunächst den folgenden Code vor hinzu // BOOKMARK 1
. Dadurch werden einige Zustandswerte für die Container festgelegt, die von unserer serverseitigen API abgerufen wurden:
const [containers, setContainers] = useState<IContainer[]>([]);
const [selectedContainer, setSelectedContainer] = useState<IContainer | undefined>(undefined);
const containerSelector = useId('containerSelector');
Fügen Sie als Nächstes den folgenden React-Hook nach // BOOKMARK 1
hinzu, um alle Container abzurufen, wenn die Seite geladen wird, und legen Sie das Zustandsobjekt fest, das sie nachverfolgt:
useEffect(() => {
(async () => {
const containers = await spe.listContainers();
if (containers) {
setContainers(containers);
}
})();
}, []);
Erstellen Sie nach der soeben hinzugefügten React-Hookimplementierung einen Ereignishandler, der ausgelöst wird, wenn ein Benutzer einen Container aus dem Dropdown-Steuerelement auswählt, das wir unserer Benutzeroberfläche hinzufügen:
const onContainerDropdownChange = (event: SelectionEvents, data: OptionOnSelectData) => {
const selected = containers.find((container) => container.id === data.optionValue);
setSelectedContainer(selected);
};
Aktualisieren Sie das Rendering, indem Sie der -Methode nach dem return()
// BOOKMARK 3
Code Folgendes hinzufügen. Dadurch werden ein DropDown
Steuerelement und ein Platzhalter erstellt, in dem eine Liste der Inhalte im ausgewählten Container hinzugefügt wird:
<div className={styles.root}>
<div className={styles.containerSelector}>
<Dropdown
id={containerSelector}
placeholder="Select a Storage Container"
className={styles.containerSelectorControls}
onOptionSelect={onContainerDropdownChange}>
{containers.map((option) => (
<Option key={option.id} value={option.id}>{option.displayName}</Option>
))}
</Dropdown>
</div>
{selectedContainer && (`[[TOOD]] container "${selectedContainer.displayName}" contents go here`)}
</div>
In diesem Code wird ein Stilobjekt verwendet, das wir der Komponente hinzugefügt haben, als wir es ursprünglich erstellt haben. Um die Formatvorlagen zu verwenden, fügen Sie den folgenden Code unmittelbar vor der -Anweisung und // BOOKMARK 3
dem return()
Kommentar hinzu:
const styles = useStyles();
Der letzte Schritt besteht darin, der App unsere neue Containers
Komponente hinzuzufügen. Suchen Und öffnen Sie die ./src/App.tsx
Datei, und fügen Sie nach den vorhandenen Importen den folgenden Import hinzu:
import Containers from "./components/containers";
Suchen Sie das <div></div>
Markup in der -Komponente return()
. Ersetzen Sie dieses Markup durch Folgendes, um unsere Containers
Komponente nur hinzuzufügen, wenn der Benutzer angemeldet ist:
<div>
{isSignedIn && (<Containers />)}
</div>
Testen der Auflistung und Auswahl von Containern
Testen Sie nun die clientseitige React-App, um die Auswirkungen unserer Änderungen zum Auflisten und Anzeigen von Containern in der React-App zu sehen.
Führen Sie über die Befehlszeile im Stammordner des Projekts den folgenden Befehl aus:
npm run start
Wenn der Browser geladen wird, melden Sie sich mit demselben Geschäfts-, Schul- und Unikonto an, das Sie verwendet haben.
Nach der Anmeldung wird die Seite neu geladen und sollte eine Liste mit Containern anzeigen, sofern Sie zuvor einen container erstellt haben.
Wenn Sie einen Container auswählen, beachten Sie, dass die bedingte Logik den Platzhalter mit dem Namen des ausgewählten Containers anzeigt:
Beenden Sie den Server durch Drücken von STRG + C in der Konsole.
Hinzufügen der Möglichkeit zum Erstellen neuer Container
In diesem Abschnitt aktualisieren Sie die serverseitige API und die React-App, um neue Contains aus unserer Webanwendung zu erstellen.
Zunächst erstellen wir die serverseitigen API-Teile zur Unterstützung der React-App.
Hinzufügen von Unterstützung zum Erstellen von Containern zum serverseitigen API-Projekt
Nun erstellen wir den Handler zum Erstellen eines Containers mithilfe von Microsoft Graph, der an unsere React-App zurückgegeben wird. Erstellen Sie eine neue Datei ./server/createContainer.ts , und fügen Sie ihr die folgenden Importe hinzu:
import {
Request,
Response
} from "restify";
import * as MSAL from "@azure/msal-node";
require('isomorphic-fetch');
import * as MSGraph from '@microsoft/microsoft-graph-client';
import { getGraphToken } from "./auth";
Fügen Sie als Nächstes den folgenden Code hinzu, um eine Instanz einer MSAL ConfidentialClientApplication
zu erstellen, die zum Abrufen des OBO-Zugriffstokens verwendet wird:
const msalConfig: MSAL.Configuration = {
auth: {
clientId: process.env['API_ENTRA_APP_CLIENT_ID']!,
authority: process.env['API_ENTRA_APP_AUTHORITY']!,
clientSecret: process.env['API_ENTRA_APP_CLIENT_SECRET']!
},
system: {
loggerOptions: {
loggerCallback(loglevel: any, message: any, containsPii: any) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: MSAL.LogLevel.Verbose,
}
}
};
const confidentialClient = new MSAL.ConfidentialClientApplication(msalConfig);
Erstellen und exportieren Sie eine neue Funktion, die folgende Aktionen ausführen soll:
- Überprüfen Sie, ob die Anforderung einen
Authorization
Header mit einem Zugriffstoken enthält. - Verwenden Sie , die dieses Token und verwenden,
ConfidentialClientApplication
um ein OBO-Token abzurufen, das wir zum Aufrufen von Microsoft Graph verwenden können. - Verwenden Sie das OBO-Token, um einen neuen
AuthenticationProvider
Client zu erstellen, den wir zum Aufrufen von Microsoft Graph verwenden.
export const createContainer = async (req: Request, res: Response) => {
if (!req.headers.authorization) {
res.send(401, { message: 'No access token provided.' });
return;
}
const [bearer, token] = (req.headers.authorization || '').split(' ');
const [graphSuccess, graphTokenRequest] = await getGraphToken(confidentialClient, token);
if (!graphSuccess) {
res.send(200, graphTokenRequest);
return;
}
const authProvider = (callback: MSGraph.AuthProviderCallback) => {
callback(null, graphTokenRequest);
};
}
Der letzte Schritt besteht darin, den Microsoft Graph-Client zu erstellen und die Anforderung zum Erstellen eines neuen Containers an einen bestimmten ContainerTypeId
zu übermitteln. Fügen Sie die folgende Code-Unmittelbarkeit vor der schließende Klammer der Funktion hinzu:
try {
const graphClient = MSGraph.Client.init({
authProvider: authProvider,
defaultVersion: 'beta'
});
const containerRequestData = {
displayName: req.body!.displayName,
description: (req.body?.description) ? req.body.description : '',
containerTypeId: process.env["CONTAINER_TYPE_ID"]
};
const graphResponse = await graphClient.api(`storage/fileStorage/containers`).post(containerRequestData);
res.send(200, graphResponse);
return;
} catch (error: any) {
res.send(500, { message: `Failed to create container: ${error.message}` });
return;
}
Fügen Sie diesen neuen Endpunkt zu unserem Restify-Server hinzu. Suchen und öffnen Sie die Datei ./server/index.ts , fügen Sie eine einzelne Import-Anweisung am Ende der vorhandenen Importe hinzu, und fügen Sie einen Listener für HTTP POST-Anforderungen an den /api/createContainers
Endpunkt hinzu:
import { createContainer } from "./createContainer";
...
server.post('/api/createContainer', async (req, res, next) => {
try {
const response = await createContainer(req, res);
res.send(200, response)
} catch (error: any) {
res.send(500, { message: `Error in API server: ${error.message}` });
}
next();
});
Aktualisieren des React-Projekts zum Erstellen eines neuen Containers
Suchen Und öffnen Sie die Datei ./src/services/spembedded.ts und fügen Sie der -Klasse den folgenden Code hinzu:
async createContainer(containerName: string, containerDescription: string = ''): Promise<IContainer | undefined> {
const api_endpoint = `${Constants.API_SERVER_URL}/api/createContainer`;
if (Providers.globalProvider.state === ProviderState.SignedIn) {
const token = await this.getApiAccessToken();
const containerRequestHeaders = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
const containerRequestData = {
displayName: containerName,
description: containerDescription
};
const containerRequestOptions = {
method: 'POST',
headers: containerRequestHeaders,
body: JSON.stringify(containerRequestData)
};
const response = await fetch(api_endpoint, containerRequestOptions);
if (response.ok) {
const containerResponse = await response.json();
return containerResponse as IContainer;
} else {
console.error(`Unable to create container: ${JSON.stringify(response)}`);
return undefined;
}
}
};
Diese neue Methode ähnelt der vorhandenen listContainers()
Methode, mit der Ausnahme, dass sie ein neues Objekt erstellt und als POST an unsere serverseitige API übermittelt.
Der letzte Schritt besteht darin, unsere Containers
Komponente zu aktualisieren, um die Benutzeroberfläche so zu aktualisieren, dass das Erstellen eines Containers unterstützt wird. Suchen Und öffnen Sie die Datei ./src/components/containers.tsx .
Für diesen Schritt verwenden wir eine React-Komponente Dialog
der Fluent-Benutzeroberfläche. Fügen Sie zunächst die folgenden Zustandsobjekte und Benutzeroberflächenkomponenten-ID-Objekte unmittelbar vor dem // BOOKMARK 1
Kommentar hinzu:
const [dialogOpen, setDialogOpen] = useState(false);
const containerName = useId('containerName');
const [name, setName] = useState('');
const containerDescription = useId('containerDescription');
const [description, setDescription] = useState('');
const [creatingContainer, setCreatingContainer] = useState(false);
Fügen Sie als Nächstes den folgenden Code unmittelbar vor dem // BOOKMARK 2
Kommentar hinzu. Diese Handler werden verwendet, um die Namens- und Beschreibungseigenschaften für den neuen Container aus den Komponenten zu aktualisieren, die Input
Dialog
sich im befinden werden. Sie werden auch verwendet, um zu behandeln, dass der Benutzer eine Schaltfläche zum Erstellen des Containers auswählt:
const handleNameChange: InputProps["onChange"] = (event: React.ChangeEvent<HTMLInputElement>, data: InputOnChangeData): void => {
setName(data?.value);
};
const handleDescriptionChange: InputProps["onChange"] = (event: React.ChangeEvent<HTMLInputElement>, data: InputOnChangeData): void => {
setDescription(data?.value);
};
const onContainerCreateClick = async (event: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
setCreatingContainer(true);
const newContainer = await spe.createContainer(name, description);
if (newContainer) {
setName('');
setDescription('');
setContainers(current => [...current, newContainer]);
setSelectedContainer(newContainer);
setDialogOpen(false);
} else {
setName('');
setDescription('');
}
setCreatingContainer(false);
}
Fügen Sie abschließend den folgenden React-Code unmittelbar nach dem schließende </Dropdown>
-Element hinzu. Dadurch wird eine React-Komponente Dialog
der Fluent-Benutzeroberfläche erstellt, die über eine Schaltfläche ausgelöst wird:
<Dialog open={dialogOpen} onOpenChange={(event, data) => setDialogOpen(data.open)}>
<DialogTrigger disableButtonEnhancement>
<Button className={styles.containerSelectorControls} appearance='primary'>Create a new storage Container</Button>
</DialogTrigger>
<DialogSurface>
<DialogBody>
<DialogTitle>Create a new storage Container</DialogTitle>
<DialogContent className={styles.dialogContent}>
<Label htmlFor={containerName}>Container name:</Label>
<Input id={containerName} className={styles.containerSelectorControls} autoFocus required
value={name} onChange={handleNameChange}></Input>
<Label htmlFor={containerDescription}>Container description:</Label>
<Input id={containerDescription} className={styles.containerSelectorControls} autoFocus required
value={description} onChange={handleDescriptionChange}></Input>
{creatingContainer &&
<Spinner size='medium' label='Creating storage Container...' labelPosition='after' />
}
</DialogContent>
<DialogActions>
<DialogTrigger disableButtonEnhancement>
<Button appearance="secondary" disabled={creatingContainer}>Cancel</Button>
</DialogTrigger>
<Button appearance="primary"
value={name}
onClick={onContainerCreateClick}
disabled={creatingContainer || (name === '')}>Create storage Container</Button>
</DialogActions>
</DialogBody>
</DialogSurface>
</Dialog>
Testen der Erstellung neuer Container
Testen Sie nun die clientseitige React-App, um die Auswirkungen unserer Änderungen zum Erstellen von Containern in der React-App zu sehen.
Führen Sie über die Befehlszeile im Stammordner des Projekts den folgenden Befehl aus:
npm run start
Wenn der Browser geladen wird, melden Sie sich mit demselben Geschäfts-, Schul- und Unikonto an, das Sie verwendet haben.
Nach der Anmeldung wird die Seite erneut geladen und sollte nun eine Schaltfläche zum Starten des Dialogfelds enthalten:
Wählen Sie die Schaltfläche Neuen Speichercontainer erstellen aus, um das Dialogfeld zu öffnen. Beachten Sie, dass die Schaltfläche deaktiviert wird, bis Sie einen Namen eingeben:
Geben Sie einen Namen und eine Beschreibung für den Container ein, und wählen Sie Speichercontainer erstellen aus. Beim Erstellen des Containers sind die Schaltflächen deaktiviert, und ein Spinner
Steuerelement zeigt dem Benutzer an, dass er funktioniert:
Sobald das Dialogfeld nicht mehr angezeigt wird, wird in der Auswahl neu der neue Container angezeigt.
Beenden Sie den Server durch Drücken von STRG + C in der Konsole.
Zusammenfassung
In dieser Übung haben Sie das vorhandene Projekt aktualisiert, um Eingebettete SharePoint-Container zu erstellen und abzurufen.