Added PnPjs with MS Graph sample. (#750)

This commit is contained in:
Sergei Sergeev 2019-01-09 18:46:24 +03:00 committed by Vesa Juvonen
parent f100c65f36
commit 9866bd646d
30 changed files with 18361 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 2
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

32
samples/react-graph-pnpjs/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
solution
temp
*.sppkg
# Coverage directory used by tools like istanbul
coverage
# OSX
.DS_Store
# Visual Studio files
.ntvs_analysis.dat
.vs
bin
obj
# Resx Generated Code
*.resx.ts
# Styles Generated Code
*.scss.ts

View File

@ -0,0 +1,12 @@
{
"@microsoft/generator-sharepoint": {
"isCreatingSolution": true,
"environment": "spo",
"version": "1.7.1",
"libraryName": "pn-p-graph-web-part",
"libraryId": "243a3aaf-cb6c-43b5-b297-133c2310a406",
"packageManager": "npm",
"isDomainIsolated": false,
"componentType": "webpart"
}
}

View File

@ -0,0 +1,55 @@
# React sample showing the use of PnPJS with MS Graph
## Summary
This webpart demonstrates how to use [PnPJS](https://pnp.github.io/pnpjs/) with SharePoint Framework and how to query [Microsoft Graph](https://docs.microsoft.com/en-us/graph/overview) with PnPJS.
It requests a list of Azure AD [groups](https://docs.microsoft.com/en-us/graph/api/group-list?view=graph-rest-1.0) at your tenant and shows them using [Office UI Fabric React](https://developer.microsoft.com/en-us/fabric#/components) list.
![Main UI](./assets/summary.png)
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/drop-1.7.1-green.svg)
## Applies to
* [SharePoint Framework](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
## Solution
Solution|Author(s)
--------|---------
react-graph-pnpjs | Sergei Sergeev ([@sergeev_srg](https://twitter.com/sergeev_srg), [spblog.net](https://spblog.net/))
## Version history
Version|Date|Comments
-------|----|--------
1.0|Jan 09, 2019|Initial release
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
---
## Minimal Path to Awesome
- clone this repo
- navigate to the folder with current sample
- restore dependencies: `$ npm i`
- bundle solution: `$ gulp bundle --ship`
- package solution: `$ gulp package-solution --ship`
- locate solution at `./sharepoint/solution/pn-p-graph-web-part.sppkg` and upload it to your tenant app catalog
- you will see a message saying that solution has pending permissions which need to be approved:
![Pending permission requests](./assets/approve.png)
- you should approve permission requests from your SharePoint Framework web part. There are [different options available](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient#manage-permission-requests) - new SharePoint Admin UI, PowerShell, [`$o365`](https://pnp.github.io/office365-cli/) cli. For the matter of this sample, the fastest way to do it is through new SharePoint Admin UI. Open Web API permission management page by navigating to the url `https://<org>-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement` (changing `<org>` to your real organization name) or by going to the new Admin UI directly from old SharePoint Admin Center. Select Pending `Group.Read.All` request and approve it:
![Approve request from new Admin UI](./assets/approve-request.png)
- run `$ gulp serve` and open hosted workbench, i.e. `https://<org>.sharepoint.com/sites/<your site>/_layouts/15/workbench.aspx`
- add `PnPGraph` web part to see it in action
## Features
Web part in this solution illustrates the following concepts on top of the SharePoint Framework:
- showcases PnPJS configuration inside SharePoint Framework
- showcases how to use MS Graph with PnPJS
- showcases how to correctly configure SharePoint Framework solution and tenant to allow PnPJS to call MS Graph
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-graph-pnpjs" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,18 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"pn-p-graph-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/pnPGraph/PnPGraphWebPart.js",
"manifest": "./src/webparts/pnPGraph/PnPGraphWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"PnPGraphWebPartStrings": "lib/webparts/pnPGraph/loc/{locale}.js"
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
"deployCdnPath": "temp/deploy"
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "pn-p-graph-web-part",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "pn-p-graph-web-part-client-side-solution",
"id": "243a3aaf-cb6c-43b5-b297-133c2310a406",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false,
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Group.Read.All"
}
]
},
"paths": {
"zippedPackage": "solution/pn-p-graph-web-part.sppkg"
}
}

View File

@ -0,0 +1,10 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://localhost:5432/workbench",
"api": {
"port": 5432,
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
"cdnBasePath": "<!-- PATH TO CDN -->"
}

7
samples/react-graph-pnpjs/gulpfile.js vendored Normal file
View File

@ -0,0 +1,7 @@
'use strict';
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
build.initialize(gulp);

17742
samples/react-graph-pnpjs/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
{
"name": "pn-p-graph-web-part",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/microsoft-graph-types": "^1.5.0",
"@microsoft/sp-core-library": "1.7.1",
"@microsoft/sp-lodash-subset": "1.7.1",
"@microsoft/sp-office-ui-fabric-core": "1.7.1",
"@microsoft/sp-webpart-base": "1.7.1",
"@pnp/common": "^1.2.7",
"@pnp/graph": "^1.2.7",
"@pnp/logging": "^1.2.7",
"@pnp/odata": "^1.2.7",
"@types/es6-promise": "0.0.33",
"@types/react": "16.4.2",
"@types/react-dom": "16.0.5",
"@types/webpack-env": "1.13.1",
"react": "16.3.2",
"react-dom": "16.3.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.7.1",
"@microsoft/sp-module-interfaces": "1.7.1",
"@microsoft/sp-tslint-rules": "1.7.0",
"@microsoft/sp-webpart-workbench": "1.7.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"ajv": "~5.2.2",
"gulp": "~3.9.1"
}
}

View File

@ -0,0 +1 @@
// A file is required to be in the root of the /src directory by the TypeScript compiler

View File

@ -0,0 +1,26 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "b8e03ec4-5e33-4da2-8281-7ea8747159e3",
"alias": "PnPGraphWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "PnPGraph" },
"description": { "default": "PnPGraph description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "PnPGraph"
}
}]
}

View File

@ -0,0 +1,71 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import * as strings from 'PnPGraphWebPartStrings';
import PnPGraph from './components/PnPGraph';
import { IPnPGraphProps } from './components/IPnPGraphProps';
import { setup as pnpSetup } from '@pnp/common';
export interface IPnPGraphWebPartProps {
description: string;
}
export default class PnPGraphWebPart extends BaseClientSideWebPart<IPnPGraphWebPartProps> {
public onInit(): Promise<void> {
pnpSetup({
spfxContext: this.context
});
return Promise.resolve();
}
public render(): void {
const element: React.ReactElement<IPnPGraphProps > = React.createElement(
PnPGraph,
{
description: this.properties.description
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}

View File

@ -0,0 +1,3 @@
export interface IPnPGraphProps {
description: string;
}

View File

@ -0,0 +1,74 @@
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.pnPGraph {
.container {
max-width: 700px;
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.row {
@include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px;
}
.column {
@include ms-Grid-col;
@include ms-lg10;
@include ms-xl8;
@include ms-xlPush2;
@include ms-lgPush1;
}
.title {
@include ms-font-xl;
@include ms-fontColor-white;
}
.subTitle {
@include ms-font-l;
@include ms-fontColor-white;
}
.description {
@include ms-font-l;
@include ms-fontColor-white;
}
.button {
// Our button
text-decoration: none;
height: 32px;
// Primary Button
min-width: 80px;
background-color: $ms-color-themePrimary;
border-color: $ms-color-themePrimary;
color: $ms-color-white;
// Basic Button
outline: transparent;
position: relative;
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
-webkit-font-smoothing: antialiased;
font-size: $ms-font-size-m;
font-weight: $ms-font-weight-regular;
border-width: 0;
text-align: center;
cursor: pointer;
display: inline-block;
padding: 0 16px;
.label {
font-weight: $ms-font-weight-semibold;
font-size: $ms-font-size-m;
height: 32px;
line-height: 32px;
margin: 0 4px;
vertical-align: top;
display: inline-block;
}
}
}

View File

@ -0,0 +1,82 @@
import { Group } from '@microsoft/microsoft-graph-types';
import { graph } from '@pnp/graph';
import {
DetailsList,
DetailsListLayoutMode,
IColumn,
IDetailsList
} from 'office-ui-fabric-react/lib/DetailsList';
import { createRef } from 'office-ui-fabric-react/lib/Utilities';
import * as React from 'react';
import { IPnPGraphProps } from './IPnPGraphProps';
export interface IState {
groups: Group[];
}
const _columns: IColumn[] = [
{
key: 'id',
name: 'Id',
fieldName: 'id',
minWidth: 50,
maxWidth: 100,
isResizable: true
},
{
key: 'name',
name: 'Name',
fieldName: 'displayName',
minWidth: 50,
maxWidth: 150,
isResizable: true
},
{
key: 'created',
name: 'Created',
fieldName: 'createdDateTime',
minWidth: 50,
maxWidth: 200,
isResizable: true
}
];
export default class PnPGraph extends React.Component<IPnPGraphProps, IState> {
private _detailsList = createRef<IDetailsList>();
constructor(props: any) {
super(props);
this.state = {
groups: null
};
}
public componentDidMount(): void {
graph.groups.get<Group[]>().then(groups => {
this.setState({
groups
});
});
}
public render(): JSX.Element {
if (!this.state.groups) {
return <div>Loading...</div>;
}
return (
<div>
<h2>Groups at your tenant:</h2>
<DetailsList
componentRef={this._detailsList}
items={this.state.groups}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
/>
</div>
);
}
}

View File

@ -0,0 +1,7 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field"
}
});

View File

@ -0,0 +1,10 @@
declare interface IPnPGraphWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
}
declare module 'PnPGraphWebPartStrings' {
const strings: IPnPGraphWebPartStrings;
export = strings;
}

View File

@ -0,0 +1,47 @@
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.2/MicrosoftTeams.schema.json",
"manifestVersion": "1.2",
"packageName": "PnPGraph",
"id": "b8e03ec4-5e33-4da2-8281-7ea8747159e3",
"version": "0.1",
"developer": {
"name": "SPFx + Teams Dev",
"websiteUrl": "https://products.office.com/en-us/sharepoint/collaboration",
"privacyUrl": "https://privacy.microsoft.com/en-us/privacystatement",
"termsOfUseUrl": "https://www.microsoft.com/en-us/servicesagreement"
},
"name": {
"short": "PnPGraph"
},
"description": {
"short": "PnPGraph description",
"full": "PnPGraph description"
},
"icons": {
"outline": "tab20x20.png",
"color": "tab96x96.png"
},
"accentColor": "#004578",
"configurableTabs": [
{
"configurationUrl": "https://{teamSiteDomain}{teamSitePath}/_layouts/15/TeamsLogon.aspx?SPFX=true&dest={teamSitePath}/_layouts/15/teamshostedapp.aspx%3FopenPropertyPane=true%26teams%26componentId=b8e03ec4-5e33-4da2-8281-7ea8747159e3",
"canUpdateConfiguration": false,
"scopes": [
"team"
]
}
],
"validDomains": [
"*.login.microsoftonline.com",
"*.sharepoint.com",
"*.sharepoint-df.com",
"spoppe-a.akamaihd.net",
"spoprod-a.akamaihd.net",
"resourceseng.blob.core.windows.net",
"msft.spoppe.com"
],
"webApplicationInfo": {
"resource": "https://{teamSiteDomain}",
"id": "00000003-0000-0ff1-ce00-000000000000"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"lib"
]
}

View File

@ -0,0 +1,30 @@
{
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
"rules": {
"class-name": false,
"export-name": false,
"forin": false,
"label-position": false,
"member-access": true,
"no-arg": false,
"no-console": false,
"no-construct": false,
"no-duplicate-variable": true,
"no-eval": false,
"no-function-expression": true,
"no-internal-module": true,
"no-shadowed-variable": true,
"no-switch-case-fall-through": true,
"no-unnecessary-semicolons": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-with-statement": true,
"semicolon": true,
"trailing-comma": false,
"typedef": false,
"typedef-whitespace": false,
"use-named-parameter": true,
"variable-name": false,
"whitespace": false
}
}

View File

@ -59,6 +59,7 @@ Deployment of SharePoint assets as part of SPFx package<br/>[react-feature-frame
React File Upload WebPart<br/>[react-file-upload](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-file-upload)|The file upload web part allowing users to upload multiple files to a document library or as item attachments.|![react-file-upload](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-file-upload/assets/SPFileUploadPreview.gif)|![drop](https://img.shields.io/badge/version-GA-green.svg)
Webpart showing Url validation for SharePoint using Office Graph<br/>[react-graph-evalurl](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-graph-evalurl)|This sample contains a class that evaluates the url input of a text field against the Microsoft Graph. It is possible to evalute the existance of the following three SharePoint Elements:|![react-graph-evalurl](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-graph-evalurl/assets/evaluation-client-searching-for-site-collection.png)|![drop](https://img.shields.io/badge/drop-1.4.1-green.svg)
Personal e-mail<br/>[react-graph-personalemail](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-graph-personalemail)|Sample React web part showing how to retrieve and display personal e-mail retrieved using the Microsoft Graph.|![react-graph-personalemail](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-graph-personalemail/assets/preview.png)|![drop](https://img.shields.io/badge/drop-1.6.0-green.svg)
PnPJS with MS Graph<br/>[react-graph-pnpjs](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-graph-pnpjs)|Sample React webpart showing PnPJS with MS Graph integration|![react-graph-pnpjs](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-graph-pnpjs/assets/summary.png)|![drop](https://img.shields.io/badge/drop-1.7.1-green.svg)
Spfx Webpart read / update MS Graph Custom Schema Extensions<br/>[react-graph-schema-extensions](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-graph-schema-extensions)|This sample shows how read and update a custom Schema extension in MS Graph. It shows how to create acustom Schema extension in Graph to store custom data related to an Office 365 Group, and how we can read and updatethat data using an spfx webpart.|![react-graph-schema-extensions](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-graph-schema-extensions/assets/webpart.png)|
Image Magnifier<br/>[react-image-magnifier](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-image-magnifier)|This web part allow to magnify an image, displaying a resolution more detailed through a lens.|![react-image-magnifier](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-image-magnifier/assets/spfx-react-image-magnifier.gif)|![drop](https://img.shields.io/badge/version-GA-green.svg)
Azure Active Directory invitation manager Graph API samples<br/>[react-invitation-manager](https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-invitation-manager)|Sample SharePoint Framework web parts built using React illustrating the possibility to use Graph API to invite external users into the Azure Active Directory.|![react-invitation-manager](https://raw.githubusercontent.com/SharePoint/sp-dev-fx-webparts/master/samples/react-invitation-manager/assets/SPFx-Invitation-Manager.gif)|![drop](https://img.shields.io/badge/drop-1.3.0-green.svg)