Added Graph thumbnail API sample

This commit is contained in:
Mikael Svenson 2020-01-21 17:02:21 +01:00
parent 917b6efdd3
commit 93bdf2ee95
19 changed files with 17424 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/js-msgraph-thumbnail/.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.10.0",
"libraryName": "thumbnail",
"libraryId": "3b1f3c00-2c12-4bd5-9a4b-d4841f223861",
"packageManager": "npm",
"isDomainIsolated": false,
"componentType": "webpart"
}
}

View File

@ -0,0 +1,64 @@
# Thumbnail/preview of pages and files in SharePoint
## Summary
A web part showcasing how to call the [Microsoft Graph Thumbnails API](https://docs.microsoft.com/en-us/graph/api/driveitem-list-thumbnails) to generate a preview image for files and pages in SharePoint. The sample illustrates how to craft the preview URL both from a search result as well as from a SharePoint item object.
The sample calls the Microsoft Graph API directly directly via the _api/2.0 endpoint in SharePoint Online, but can easily be changed to call the Graph API endpoint directly for scenarios outside of SharePoint as long as an access token is retrieved.
The goal of the sample is to illustrate a single call calling pattern for the thumbnail with the following calling pattern:
<pre>
&lt;img src="<i><b>&lt;endpoint&gt;</b>/sites/<b>&lt;site id&gt;</b>/lists/<b>&lt;list id&gt;</b>/items/<b>&lt;item id&gt;</b>/driveItem/thumbnails/0/<b>&lt;custom size&gt;</b>/content</i>">
</pre>
| Token | Description |
---|---
|endpoint| graph.microsoft.com/v1.0 <br/> tenant.sharepoint.com/_api/v2.0
|site id | Site object id - GUID. |
|list id | List object id - GUID. |
|item id | ListItem object id or unique id - Integer/GUID. |
|custom size | See [Requesting custom thumbnail sizes](https://docs.microsoft.com/en-us/graph/api/driveitem-list-thumbnails?view=graph-rest-1.0&tabs=http#requesting-custom-thumbnail-sizes) in the official Microsoft Graph documentation.
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/drop-1.10.0-green.svg)
## Applies to
* [SharePoint Framework Release GA](https://blogs.office.com/2017/02/23/sharepoint-framework-reaches-general-availability-build-and-deploy-engaging-web-parts-today/)
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
## Solution
Solution|Author(s)
--------|---------
js-msgraph-thumbnail | Mikael Svenson ([@mikaelsvenson](http://www.twitter.com/mikaelsvenson), [techmikael.com](techmikael.com))
## Version history
Version|Date|Comments
-------|----|--------
1.0|January 21st, 2020|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
### Local testing
- Clone this repository
- In the command line run:
- `npm install`
- `gulp serve`
### Deploy
* gulp clean
* gulp bundle --ship
* gulp package-solution --ship
* Upload the js-msgraph-thumbnail.sppkg file from sharepoint\solution to your tenant App Catalog
* E.g.: https://&lt;tenant&gt;.sharepoint.com/sites/AppCatalog/AppCatalog
* Add the web part *Thumbnail* to a site collection where you have files in the `Shared Documents` folder, and test it on a page.
* Change `const libraryPath = "Shared Documents";` if you want to target `SitePages` or a different library.
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/js-msgraph-thumbnail" />

View File

@ -0,0 +1,14 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"thumbnail-web-part": {
"components": [{
"entrypoint": "./lib/webparts/thumbnail/ThumbnailWebPart.js",
"manifest": "./src/webparts/thumbnail/ThumbnailWebPart.manifest.json"
}]
}
},
"externals": {},
"localizedResources": {}
}

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": "thumbnail",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,13 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "thumbnail-client-side-solution",
"id": "3b1f3c00-2c12-4bd5-9a4b-d4841f223861",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false
},
"paths": {
"zippedPackage": "solution/js-msgraph-thumbnail.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 -->"
}

View File

@ -0,0 +1,7 @@
'use strict';
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(require('gulp'));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
{
"name": "thumbnail",
"version": "0.0.1",
"private": true,
"main": "lib/index.js",
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/sp-core-library": "1.10.0",
"@microsoft/sp-lodash-subset": "1.10.0",
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
"@microsoft/sp-property-pane": "1.10.0",
"@microsoft/sp-webpart-base": "1.10.0",
"@pnp/common": "^1.3.8",
"@pnp/logging": "^1.3.8",
"@pnp/odata": "^1.3.8",
"@pnp/sp": "^1.3.8",
"@types/es6-promise": "0.0.33",
"@types/webpack-env": "1.13.1"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.10.0",
"@microsoft/sp-tslint-rules": "1.10.0",
"@microsoft/sp-module-interfaces": "1.10.0",
"@microsoft/sp-webpart-workbench": "1.10.0",
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
"gulp": "~3.9.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"ajv": "~5.2.2"
}
}

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": "2393ac1e-1f06-403e-a8cb-0e64f3079274",
"alias": "ThumbnailWebPart",
"componentType": "WebPart",
"version": "*",
"manifestVersion": 2,
"requiresCustomScript": false,
"supportedHosts": [
"SharePointWebPart"
],
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": {
"default": "Other"
},
"title": {
"default": "Thumbnail"
},
"description": {
"default": "Thumbnail description"
},
"officeFabricIconFontName": "ThumbnailView",
"properties": {}
}]
}

View File

@ -0,0 +1,79 @@
import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { sp, Web, RenderListDataOptions } from "@pnp/sp";
let _documentResults: string = "";
let _searchResults: string = "";
export default class ThumbnailWebPart extends BaseClientSideWebPart<void> {
public async onInit(): Promise<void> {
let web: Web = new Web(this.context.pageContext.web.absoluteUrl);
const noRedirect = "?preferNoRedirect=true"; // undocumented, to avoid a redirect to CDN
//const noRedirect = "";
const libraryPath = "Shared Documents";
// const libraryPath = "SitePages";
// Using renderListDataAsStream for ease of use to also get the List ID on one call
let options : RenderListDataOptions = RenderListDataOptions.ListData | RenderListDataOptions.ContextInfo;
let fileData = await web.getList(`${this.context.pageContext.web.serverRelativeUrl}/${libraryPath}`).renderListDataAsStream({
RenderOptions: options ,
ViewXml: "<View Scope='Recursive'><ViewFields><FieldRef Name='FileLeafRef' /><FieldRef Name='UniqueId' /></ViewFields><RowLimit Paged='TRUE'>10</RowLimit></View>"
});
let searchResults = await sp.search({
Querytext: `path:"${this.context.pageContext.web.absoluteUrl}/${libraryPath}" IsDocument:1`,
RowLimit: 10,
SelectProperties: ["FileName", "DocumentLink", "NormSiteID", "ParentLink", "SPWebUrl", "NormListID", "NormUniqueID"]
});
// Thumbnail URL docs
// https://docs.microsoft.com/en-us/graph/api/driveitem-list-thumbnails
// When using custom thumbnails:
// The thumbnail returned may not exactly match the pixel dimensions that was requested,
// but will match the aspect ratio. In some cases, a larger thumbnail may be returned than was requested,
// if the thumbnail already exists and can easily be scaled to match the requested resolution.
// Often it's better to request one of the default sizes
const maxHeight = "c99999x150";
//const maxWidth = "c150x99999";
let listId = fileData["listName"].replace(/[{}]/g, "");
fileData.ListData.Row.forEach(fileInfo => {
let itemUniqueId = fileInfo["UniqueId"].replace(/[{}]/g, "");
let fileName = fileInfo["FileLeafRef"];
let thumbnailUrl = `/_api/v2.0/sites/${this.context.pageContext.site.id}/lists/${listId}/items/${itemUniqueId}/driveItem/thumbnails/0/${maxHeight}/content${noRedirect}`;
_documentResults += (`<li>${fileName}<br/><img height="150" border="1" src="${thumbnailUrl}"></li>`);
});
searchResults.PrimarySearchResults.forEach(item => {
let thumbnailUrl = `/_api/v2.0/sites/${item["NormSiteID"]}/lists/${item["NormListID"]}/items/${item["NormUniqueID"]}/driveItem/thumbnails/0/${maxHeight}/content${noRedirect}`;
_searchResults += (`<li>${item["FileName"]}<br/><img height="150" border="1" src="${thumbnailUrl}"></li>`);
});
}
public render(): void {
this.domElement.innerHTML = `
<div>
<h3>REST loaded</h3>
<ul>
${_documentResults}
</ul>
<h3>Search loaded</h3>
<ul>
${_searchResults}
</ul>
</div>`;
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
}

View File

@ -0,0 +1,38 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"inlineSources": false,
"strictNullChecks": false,
"noUnusedLocals": false,
"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
}
}