10 Lab Share Point Framework and React

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 15

Error! No text of specified style in document.

1.1 LAB – REACT COMPONENTS - LISTING THE SITE PER MISSIONS


In this lab we will focus on creating React components. We will use the Yeoman generator to create a React project.
The target of this project is to list all the permissions on the current site. When we click one of the groups we will list
the group members.
To get all the information we will use the SharePoint REST services.
To style the components we will use the available office ui fabric styles.

1.1.1 CREATING THE PROJECT


Start a node command prompt. Move to the folder (cd) where you want to create the project.
To create a new Framework project we will run the yeoman generator with the “@microsoft/sharepoint” template.

c:\Labs>yo @microsoft/sharepoint

The SharePoint Client-side Solution Generator should now start!

Now let’s step through the wizard. Add the following details:
1. Solution name: SitePermissionsSolution
2. Files location: Pick “Create a subfolder with solution name” (use the arrow keys)
3. Baseline packages: SharePoint Online only
4. Feature deployment: y
5. Require permissions to access web APIs: N
6. Client-side component type: WebPart
7. Webpart name: ListSitePermissions
8. Webpart description: Displays the current site permissions
9. Framework: Pick “React”

Check that there are no errors when creating the web part. Open up Visual Studio Code and run the project by
running the following commands within the newly created folder:

code .
gulp serve

1.1.2 MODIFY THE GENERATED WEB PART CLASS


We are not going to use any web part properties or translated labels so let’s remove the following code

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
2 Error! No text of specified style in document.

LISTSITEPERMISSIONSWEBPART.TS

import {
BaseClientSideWebPart,
IPropertyPaneConfiguration
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import * as strings from 'listSitePermissionsStrings';

Also, modify the getPropertyPaneConfiguration method

LISTSITEPERMISSIONSWEBPART.TS

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {


return {
pages: []
};
}

Now, let’s remove the default description property from the web part interface

LISTSITEPERMISSIONSWEBPART.TS

export interface IListSitePermissionsWebPartProps {


description: string;
}

As you can see, this web part loads a single React component ListSitePermissions and injects it into the DOM. In that
main component however we do want to use the web part context. We need it to get the current site url and the http
client. We will modify the component properties, so we can pass it in, and then set it from the web part code.

COMPONENTS/ILISTSITEPERMISSIONSPROPS.TS

import {
IWebPartContext
} from '@microsoft/sp-webpart-base';

import {
IListSitePermissionsWebPartProps
} from '../ListSitePermissionsWebPart';

export interface IListSitePermissionsProps extends IListSitePermissionsWebPartProps


{
context: IWebPartContext;
}

In the web part code, you should now see that our element cannot be initialised properly. We need to modify the
passed in properties. Remove description, add context.

LISTSITEPERMISSIONSWEBPART.TS

public render(): void {


const element: React.ReactElement<IListSitePermissionsProps> =
React.createElement(ListSitePermissions, {
context: this.context
});
ReactDom.render(element, this.domElement);
}

Modify the render method of the main component so that we can build the project.

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 3

LISTSITEPERMISSIONS.TSX

public render(): React.ReactElement<IListSitePermissionsProps> {


return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
Permissions loading!
</div>
</div>
);
}

We will not change this web part any more during this lab. Build your project and check for errors.

1.1.3 CREATING THE MAIN CO MPONENT


The main component has already been generated for us at
src/webparts/ListSitePermissions/components/ListSitePermissions.tsx. We will keep this component and use it as the
root component of our web part. Later we will create two child components, PermissionList and GroupDetails.
As this component is the parent component it will host the data, thus the state. Because we are using TypeScript, we
can make this state typed. For this we will first create some interfaces. We want to store the permissionset of the
current site.
Need more info on the REST and security structure we are going to use, look at the following link:
https://msdn.microsoft.com/en-us/library/office/dn531432.aspx
Structure:
RoleAssignment - /_api/web/roleassignments
- Member - /_api/web/roleassignments/GetByPrincipalId(id)/member
o User/Group
 Group - /_api/Web/sitegroups/getbyid(id)/users
 User
- RoleDefinitionBindings - /_api/web/roleassignments/GetByPrincipalId(id)/roledefinitionbindings
o Role

We can bring all of this together with some expand statements:


/_api/web/roleassignments?$expand=Member,Member/Users,RoleDefinitionBindings&$select=PrincipalId,Membe
r/Title,Member/ID,Member/PrincipalType,Member/Users/Title,RoleDefinitionBindings/Id,RoleDefinitionBindings/
Name
Testing this REST call this is what we get back:

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
4 Error! No text of specified style in document.

Let’s create interfaces to store this data. It’s important to have interface members with exactly the same name and
casing as in the http response, this will make things a lot easier in our code. Instead of mapping everything manually
we will just send the original json response to our components to render our data.
First, create a new folder under src called interfaces.
Create a new file in this folder called PermissionInterfaces.ts and add the following code:

/SRC/INTERFACES/PERMISSIONINTERFACES.TS

export interface ISPRoleAssignment{


PrincipalId:number;
Member:ISPMemberInfo;
RoleDefinitionBindings:ISPRoleDefinitionBinding[];
}

export interface ISPMemberInfo{


Id:number;
Title:string;
PrincipalType:MemberType;
Users?:ISPUser[];
}

export enum MemberType{


Group = 8,
User = 1
}

export interface ISPRoleDefinitionBinding{


Id:number;
Name:string;
}

export interface ISPUser{


Title:string;

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 5

Now that we have our data structures, we can use them to create the state for our main component. The first thing
we will need again is a state interface. That interface will contain our permission set.
Make sure you use the interface when defining the component.
Add the following:

LISTSITEPERMISSIONS.TSX

import { ISPRoleAssignment } from '../../../../interfaces/PermissionInterfaces';

export interface IListSitePermissionsState {


permissions: ISPRoleAssignment[];
}

export default class ListSitePermissions extends


React.Component<IListSitePermissionsProps, IListSitePermissionsState> {
public render(): React.ReactElement<IListSitePermissionsProps> {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
Permissions loading!
</div>
</div>
);
}
}

Let’s add a constructor to set the initial state. Let’s also implement the componentDidMount method to load the site
permission set when our component is loaded. The IWebPartContext interface needs to be imported.

LISTSITEPERMISSIONS.TSX

import { IWebPartContext } from '@microsoft/sp-webpart-base';



export default class ListSitePermissions extends … {
constructor(props:{context:IWebPartContext}){
super(props);
//set initial state
this.state = { permissions: [] };
}
public componentDidMount() :void{
//we will set the data here! I needz the method!
}

}

Run or build the project and check that everything builds fine.
Hope everything works just fine? Impressive, isn’t it .

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
6 Error! No text of specified style in document.

1.1.4 WRITE THE HTTP SERVI CE


Before we continue, let’s write the http service class that will connect to the SharePoint REST services.
Let’s actually get some data. For this we will create a separate code file, as this might be something we will need in
other components.
In the src folder add a new folder services. Add a new file and name it PermissionsHttpService.ts.
We will need a context object to access the http client, so add the following code:

PERMISSIONSHTTPSERVICE.TS

import {
IWebPartContext
} from '@microsoft/sp-webpart-base';

export default class PermissionsHttpService {

private _context: IWebPartContext;

constructor(context:IWebPartContext){
this._context = context;
}
}

Let’s first implement a method that will give us the role assignment collection. This method will return a collection of
ISPRoleAssignment, so add the import for the interface as well.

PERMISSIONSHTTPSERVICE.TS

import { ISPRoleAssignment } from '../interfaces/PermissionsInterfaces';

import {
SPHttpClient, SPHttpClientResponse
} from '@microsoft/sp-http';

export default class PermissionsHttpService {

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 7


private _roleAssignmentUrl =
"/_api/web/roleassignments?$expand=Member,Member/Users,RoleDefinitionBindings&$sele
ct=PrincipalId,Member/Title,Member/ID,Member/PrincipalType,Member/Users/Title,RoleD
efinitionBindings/Id,RoleDefinitionBindings/Name";

public GetRoleAssignmentData(): Promise<ISPRoleAssignment[]> {


return this._context.spHttpClient
.get(
this._context.pageContext.web.absoluteUrl + this._roleAssignmentUrl,
SPHttpClient.configurations.v1
)
.then((data:SPHttpClientResponse) => data.json() as
Promise<{value:ISPRoleAssignment[]}>)
.then(jsonData => jsonData.value)
.catch(err => {
console.log(err);
return [];
});

}
}

Notice in this case we return the json as is, we’re not mapping anything manually. Be aware this will include the odata
metadata and send it to our components. If you want to avoid this overhead, map everything manually!
Great! Now let’s get back to our component!

1.1.5 SHOW THE DATA IN THE COMPONENT


Let’s set the state in the component and then show it in the interface!

LISTSITEPERMISSIONS.TSX

import PermissionsHttpService from '../../../services/PermissionsHttpService';



export default class ListSitePermissions
extends React.Component<IListSitePermissionsProps, IListSitePermissionsState> {

constructor(props:{context:IWebPartContext}){
super(props);
//set initial state
this.state = {permissions: [] };

//set service
this._permissionsHttpService = new PermissionsHttpService(this.props.context);

private _permissionsHttpService: PermissionsHttpService;

public componentDidMount(): void {


this._permissionsHttpService.GetRoleAssignmentData().then(
(roleAssignments: ISPRoleAssignment[]) => {
console.log(roleAssignments);
this.setState({
permissions: roleAssignments
});
}
);
}

}

Good good. Let’s see if it works! Open your SharePoint Online Workbench and check the console output!
This will not work in your local workbench!

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
8 Error! No text of specified style in document.

1.1.6 CREATING A PERMISSION OVERVIEW COMPONENT

We could show all that glorious data in our main component, but this lab is about react components right . Let’s
create a component that will display the permission set.
Add a new folder Permissions inside the components folder. In that folder create a new component file, named
PermissionList.tsx.
Let’s add the react component code and the property interface we will need! In this component we will also use css
and react css tools, so let’s import them already!

PERMISSIONLIST.TSX

import * as React from 'react';


import {css} from 'office-ui-fabric-react';
import styles from '../ListSitePermissions.module.scss';

import { ISPRoleAssignment, MemberType } from


'../../../../interfaces/PermissionInterfaces';

export interface IPermissionListProps {


permissions: ISPRoleAssignment[];
}

export default class PermissionList


extends React.Component<IPermissionListProps,{}>{
}

Implement the render method to show the permissionset.

PERMISSIONLIST.TSX

public render(): React.ReactElement<IPermissionListProps> {


//console.log("rendering");
var roles = this.props.permissions.map(
(roleAss:ISPRoleAssignment) => {

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 9

return (
<div>{roleAss.Member.Title}</div>
);
}
);
return (
<div className="ms-Grid ms-fontColor-black">
<div className="ms-Grid-row ms-font-xl ms-fontColor-themePrimary">Who
has access to this site?</div>
{roles}
</div>
);
}

That should be enough for now. Yes, we will make it look pretty in a moment!

1.1.7 ADD THE PERMISSION OVERVIEW COMPONENT TO THE MAIN COMPONENT


Now we can use the component by importing it. We set the permissionSet property through the attributes.

LISTSITEPERMISSIONS.TSX

import PermissionList from './Permissions/PermissionList';

public render(): React.ReactElement<IListSitePermissionsProps> {


return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
<PermissionList permissions={this.state.permissions} />
</div>
</div>
);
}

Check the output!

1.1.8 FINALIZE THE PERMISSION OVERVIEW COMPONE NT


Now, we will add some css (sass) to make the component look good! We will also need to modify the render method
of course.
No good-looking output without styling, so let’s go and implement the custom styles first.
replace the contents of the existing file with this css:

LISTSITEPERMISSIONS.MODULE.SCSS

@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';

.listSitePermissions {
.container {
margin: 0px auto;
}
.row {
padding:3px;
cursor: pointer;
}

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
10 Error! No text of specified style in document.

.element{
margin-right: 2px;
padding:8px 10px 2px;
color:white;
min-height:35px;
vertical-align: middle;
}
.inline{
margin-right: 5px;
padding: 2px 5px;
border:1px dashed white;
}
.icon{
font-size: 20px;
margin-right: 10px;
}
}

Modify the render method to make each role assignment look good. We will add an icon (office-ui-fabric) to show if it
is a user or a group. Also, we’ll get the list of role bindings and render them in html.

PERMISSIONLIST.TSX

public render(): React.ReactElement<IPermissionListProps> {


var roles = this.props.permissions.map(
(roleAss:ISPRoleAssignment) => {
var roleBindingsHTML = roleAss.RoleDefinitionBindings.map(element =>
<span className={styles.inline}
key={element.Id}>{element.Name}</span>
);
return (
<div className={css('ms-Grid-row', styles.row)} role="row"
key={roleAss.PrincipalId}>
<div className={css('ms-Grid-col ms-u-sm11 ms-u-lg5 ms-bgColor-
themePrimary', styles.element)} >
<i className={css(`ms-Icon ms-Icon--
${roleAss.Member.PrincipalType === MemberType.User ? 'Contact':'Group'}`,
styles.icon)}></i>
{roleAss.Member.Title}
</div>
<div className={css('ms-Grid-col ms-u-sm11 ms-u-lg6 ms-bgColor-
themePrimary', styles.element)} >
{roleBindingsHTML}
</div>
</div>
);
}
);
return (
<div className="ms-Grid ms-fontColor-white">
<div className="ms-Grid-row ms-font-xl ms-fontColor-themePrimary">Who
has access to this site?</div>
{roles}
</div>
);
}

Test!
Aaaaah better…

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 11

That concludes the first part of this lab. Good job!


In the next part we will implement the code to select a group and display it’s members in a separate component.
If you were fast, and everyone is still hard at work, just keep going!

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
12 Error! No text of specified style in document.

1.2 VIEWING GROUP MEMBERS


Now that we can look at the permission set, we want to be able to select a group and show the members. For this, we
will add a second component.
First let’s implement the select logic on the PermissionList component!

1.2.1 ADD SELECT TO PERMIS SIONLIST COMPONENT


Add an event property to the main component. This will be an optional value as we start without selection.

PERMISSIONLIST.TSX

export interface IPermissionListProps {


permissions: ISPRoleAssignment[];
onRoleAssignmentSelect?: any;
}

Let’s trigger the property from a function. Add it to the component class

PERMISSIONLIST.TSX

private selectRoleAssignment(role:ISPRoleAssignment, event): void{


this.props.onRoleAssignmentSelect(role);
}

Final step: call the function when somebody clicks a data row!

PERMISSIONLIST.TSX

public render(): React.ReactElement<IPermissionListProps> {



return (
<div className={css('ms-Grid-row', styles.row)} role="row"
key={roleAss.PrincipalId} onClick={this.selectRoleAssignment.bind(this, roleAss)}>

</div>
);

1.2.2 USE EVENT ON THE MAIN COMPONENT


The PermissionList item in the render method of ListSitePermissions is now supporting our new property. Let’s
handle the event! Notice the arrow function, this will make sure the event handler runs in the context of the current
component instance.

LISTSITEPERMISSIONS.TSX

public render(): React.ReactElement<IListSitePermissionsProps> {


return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
<PermissionList permissionSet={this.state.permissionSet}
onRoleAssignmentSelect={(ra) => this.handleRoleAssignmentSelect(ra)} />
</div>
</div>
);
}

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 13

Now, let’s implement the handleRoleAssignmentSelect method. We will store the selected object in the state, so let’s
extend that first.

LISTSITEPERMISSIONS.TSX

export interface IListSitePermissionsState {


permissions: ISPRoleAssignment[];
selectedRoleAssignment?: ISPRoleAssignment;
}

Add this method inside the class:

private handleRoleAssignmentSelect(roleAssignment:ISPRoleAssignment): void{


console.log(roleAssignment);
this.setState({
selectedRoleAssignment:roleAssignment
});
}

Test your project in the SharePoint Online workbench!


Make sure you see the selected role assignment object in the console output.

1.2.3 CREATE THE GROUP DETAILS COMPONENT


Now that we have our selected group object, we want to show it’s members!
For this, we will create a new component. Add a new file to the components/permissions folder named
GroupDetails.tsx.
The properties will contain the selected role assignment and it’s users.

GROUPDETAILS.TSX

import * as React from 'react';

import { css } from 'office-ui-fabric-react';


import styles from '../ListSitePermissions.module.scss';

import { ISPUser, ISPRoleAssignment } from


'../../../../interfaces/PermissionInterfaces';

export interface IGroupDetailsProps {


selectedRoleAssignment?: ISPRoleAssignment;
}

export default class GroupDetails extends React.Component<IGroupDetailsProps, {}>{


}

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
14 Error! No text of specified style in document.

1.2.4 USE THE MEMBER DATA IN THE COMPONENT


Now, let’s render the user data!

GROUPDETAILS.TSX

public render(): React.ReactElement<IGroupDetailsProps> {


if (!this.props.selectedRoleAssignment ||
!this.props.selectedRoleAssignment.Member.Users) {
return <div />;
} else {
var users = this.props.selectedRoleAssignment.Member.Users.map((user:
ISPUser) =>
<div className={css('ms-Grid-col ms-u-sm11 ms-u-md3 ms-bgColor-
themePrimary', styles.element)} key={user.Title}>{user.Title}</div>
);
return (
<div className="ms-Grid ms-fontColor-white">
<div className="ms-Grid-row ms-u-sm11 ms-font-xl ms-fontColor-
themePrimary">Group Members</div>
<div className="ms-Grid-row">
{users}
</div>
</div>
);
}
}

1.2.5 ADD THE GROUP DETAILS COMPONENT TO MAIN COMPONENT


Now let’s use our new component. Add it to the main component.

LISTSITEPERMISSIONS.TSX

import GroupDetails from './permissions/GroupDetails';



public render(): JSX.Element {
return (
<div className={styles.listSitePermissions}>
<div className={styles.container}>
<PermissionList permissionSet={this.state.permissionSet}
onRoleAssignmentSelect={this.handleRoleAssignmentSelect} />
<GroupDetails selectedRoleAssignment={this.state.selectedRoleAssignment} />
</div>
</div>
);
}

Test!

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net
Error! No text of specified style in document. 15

Copyright 2000-2010 by U2U nv/sa, Belgium – For use in U2U courses only. Visit www.u2u.net

You might also like