added new react-graph-evalurl sample (#492)

This commit is contained in:
Stefan Bauer 2018-04-27 17:24:58 +02:00 committed by Vesa Juvonen
parent 934d1d92d1
commit 81e5367231
27 changed files with 18711 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-evalurl/.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,8 @@
{
"@microsoft/generator-sharepoint": {
"version": "1.4.1",
"libraryName": "react-graph-evalurl",
"libraryId": "46731e63-80f2-4711-92ce-48173b10f0c8",
"environment": "spo"
}
}

View File

@ -0,0 +1,103 @@
## Webpart showing Url validation for SharePoint using Office Graph
### Summary
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:
* Site Collection
* Web Site
* Lists and Document libraries
The web part shows all those three example and the reuslt returned by the Microsoft Graph.
![Evaluation Client searching for suitable site collection][figure1]
### Usage
To evaluate the web part the input for site collection, web site or list and document library simply place a URL from your tennant in one of the text fields shown above. After the text field loses `onblur` its focus the evaluation happens automatically in the background and showing the debug information in the debugging information.
![Evaluation of web site with current debug informations][figure2]
### Project Setup and important files
```txt
src
└── webparts
└── graphEvalUrl
├── GraphEvalUrlWebPart.manifest.json
├── GraphEvalUrlWebPart.ts
├── components
│   ├── GraphEvalClient.ts **<-- Evalution Class**
│   ├── GraphEvalDebug.tsx **<-- Debug Panel Component**
│   ├── GraphEvalUrl.module.scss
│   ├── GraphEvalUrl.module.scss.ts
│   ├── GraphEvalUrl.tsx **<-- Demo Control for web part**
│   └── IGraphEvalUrlProps.ts
└── loc
├── en-us.js
└── mystrings.d.ts
```
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/drop-1.4.1-green.svg)
## Demo
![Evaluation of web site with current debug informations][figure3]
## Applies to
* [SharePoint Framework Developer Preview](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-evalurl|Stefan Bauer (MVP, Stefan Bauer - N8D, [@stfbauer](https://twitter.com/stfbauer) )
## Version history
Version|Date|Comments
-------|----|--------
1.0.0|April 15, 2018|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.**
---
## Prerequisites
- SharePoint Online tenant with Office Graph content
- Site Collection created under the **/sites/** or **/**
## Minimal Path to Awesome
- clone this repo
- `$ npm i`
- `$ gulp serve --nobrowser`
- Open workbench on your tennant, ie. https://contoso.sharepoint.com/sites/salestesm/_layouts/15/workbench.aspx
- Search and add web part "Graph - Eval Url"
## Features
This sample web part shows how URLs in SharePoint can be checked and evaluated agains the Microsoft Graph. This scenario and the introduced class can be use to evluate not only user input but can also be used in the configuration panel of web parts. The benefit is that the URL of the target location remains visible and can be use for debugging reasons to.
The class returns all the Graph objects identified during the evaluation process. It can also be used in backend code.
- using React for building SharePoint Framework Client-side Web Parts
- using Office UI Fabric React components
- create additional custom react components
- access information from the Microsoft Graph using SharePoint Framework version 1.4.1 and above
- using ES6 Promises with vanilla-JavaScript web requests
## Limitations
To identify a list or document library the following two token will be use:
* 'Forms' - View or SharePoint List Form for document libraries
* 'Lists' - SharePoint stores all lists in the sub folder lists so this will be use to identify if a list is present in the URL
[figure1]: ./assets/evaluation-client-searching-for-site-collection.png
[figure2]: ./assets/eval-web-after-site-collection.png
[figure3]: ./assets/url-graph-eval.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

View File

@ -0,0 +1,18 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"graph-eval-url-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/graphEvalUrl/GraphEvalUrlWebPart.js",
"manifest": "./src/webparts/graphEvalUrl/GraphEvalUrlWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"GraphEvalUrlWebPartStrings": "lib/webparts/graphEvalUrl/loc/{locale}.js"
}
}

View File

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

View File

@ -0,0 +1,7 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "react-graph-evalurl",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,12 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "react-graph-evalurl-client-side-solution",
"id": "46731e63-80f2-4711-92ce-48173b10f0c8",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/react-graph-evalurl.sppkg"
}
}

View File

@ -0,0 +1,10 @@
{
"$schema": "https://dev.office.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,45 @@
{
"$schema": "https://dev.office.com/json-schemas/core-build/tslint.schema.json",
// Display errors as warnings
"displayAsWarning": true,
// The TSLint task may have been configured with several custom lint rules
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
// project). If true, this flag will deactivate any of these rules.
"removeExistingRules": true,
// When true, the TSLint task is configured with some default TSLint "rules.":
"useDefaultConfigAsBase": false,
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
// which are active, other than the list of rules below.
"lintConfig": {
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
"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-case": true,
"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,
"valid-typeof": true,
"variable-name": false,
"whitespace": false
}
}
}

View File

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

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);

17532
samples/react-graph-evalurl/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
{
"name": "react-graph-evalurl",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"react": "15.6.2",
"react-dom": "15.6.2",
"@types/react": "15.6.6",
"@types/react-dom": "15.5.6",
"@microsoft/sp-core-library": "~1.4.1",
"@microsoft/sp-webpart-base": "~1.4.1",
"@microsoft/sp-lodash-subset": "~1.4.1",
"@microsoft/sp-office-ui-fabric-core": "~1.4.1",
"@types/webpack-env": ">=1.12.1 <1.14.0"
},
"devDependencies": {
"@microsoft/sp-build-web": "~1.4.1",
"@microsoft/sp-module-interfaces": "~1.4.1",
"@microsoft/sp-webpart-workbench": "~1.4.1",
"gulp": "~3.9.1",
"@types/chai": ">=3.4.34 <3.6.0",
"@types/mocha": ">=2.2.33 <2.6.0",
"ajv": "~5.2.2"
}
}

View File

@ -0,0 +1,26 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "92bdb2d9-57de-40a5-93d5-6941b90038b2",
"alias": "GraphEvalUrlWebPart",
"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": "Graph - Eval Url" },
"description": { "default": "Evaluates Site Collection, Web, list or document library using Microsoft Graph" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "Shows how to evaluate URL using Microsoft Graph"
}
}]
}

View File

@ -0,0 +1,57 @@
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 'GraphEvalUrlWebPartStrings';
import GraphEvalUrl from './components/GraphEvalUrl';
import { IGraphEvalUrlProps } from './components/IGraphEvalUrlProps';
export interface IGraphEvalUrlWebPartProps {
description: string;
}
export default class GraphEvalUrlWebPart extends BaseClientSideWebPart<IGraphEvalUrlWebPartProps> {
public render(): void {
const element: React.ReactElement<IGraphEvalUrlProps > = React.createElement(
GraphEvalUrl,
{
description: this.properties.description,
graphClient: this.context.graphHttpClient
}
);
ReactDom.render(element, 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,450 @@
import {
GraphHttpClient, HttpClientResponse,
} from '@microsoft/sp-http';
export default class GraphEvalClient {
_context: any;
_graphClient: GraphHttpClient;
_urlToEvaluate: URL;
_isList = false;
_isLibrary = false;
constructor(graphClient: any) {
// use locally stored graphHttpClient
this._graphClient = graphClient;
}
private _getUrlJunks(urlPath: string): string[] {
return urlPath
.toLowerCase() // convert urlPath to lowerstring
.split('\/') // split out all slashes
// Filter all empty values
.filter((junk) => {
if (junk !== '') {
return junk;
}
})
}
/**
* Assume the site collectio on an URL
* @param urlPath URL that should be evaluated
*/
private _getSiteCollectionUrl(urlPath: string): string {
let urlPathElements = this._getUrlJunks(urlPath);
// Use the root site collection
if (urlPathElements[0] !== 'sites') {
return ''
}
// found sub site collection and use only /sites/<your subweb>
if (urlPathElements.length >= 2) {
// assumes we have a /sites/something
return `/${urlPathElements[0]}/${urlPathElements[1]}/`
}
}
/**
* Assume the url on an URL
* @param urlPath URL that should be evaluated
*/
private _getAssumedWeburl(urlPath: string) {
let siteColleciton = this._getSiteCollectionUrl(urlPath),
urlPathElements = this._getUrlJunks(urlPath);
/* Get location if there is for form or lists to identify
docuemnt library or list
*/
let formLocation = urlPathElements.indexOf('forms'),
listLocation = urlPathElements.indexOf('lists'),
sitePages = urlPathElements.indexOf('sitepages');
/* Check if it is a full list url
* otherwise check if it is a list
* otherwise truncate the path for ine level
*/
if (formLocation !== -1) {
this._isLibrary = true;
return `/${urlPathElements.slice(0, formLocation - 1).join('/')}`;
} else if (listLocation !== -1) {
this._isList = true;
return `/${urlPathElements.slice(0, listLocation).join('/')}`;
} else if (sitePages !== -1) {
console.log(urlPathElements.slice(0, sitePages));
return `/${urlPathElements.slice(0, sitePages).join('/')}`;
} else {
// just return path one higher then the final web or list in case no one have entered no view
return `/${urlPathElements.slice(0, urlPathElements.length).join('/')}`;
}
}
/**
* Assume the list or library url based on a path
* @param urlPath URL that should be evaluated
*/
private _getAssumedList(urlPath: string) {
let webUrl = this._getAssumedWeburl(urlPath),
urlPathElements = this._getUrlJunks(urlPath);
// Check if a list should be found otherwise docuemnt library or unspecified
if (this._isList) {
let listIndex = urlPathElements.indexOf('lists');
// +2 for adding /lists/<listname>
return urlPathElements.slice(0, listIndex + 2).join('/');
} else if (this._isLibrary) {
let formIndex = urlPathElements.indexOf('forms');
/*
No additional index needs to be added bcause document libraries already exist
in root folder of Site Collection
*/
return `/${urlPathElements.slice(0, formIndex).join('/')}`;
} if (urlPathElements[urlPathElements.length - 1].indexOf('.apsx')) {
return `/${urlPathElements.slice(0, urlPathElements.length - 1).join('/')}`;
} else {
throw 'Neither list nor document library could be identified';
}
}
/**
* Try to parse the url to a JavaScript Url Object
* @param url
*/
private _evaluateUrl(url: string) {
console.log(url);
try {
return new URL(url)
} catch (Exception) {
throw Exception;
}
}
/**
* Graph query to resturn a site collection or web
* @param hostname
* @param scUrl
*/
private _evaluateWeb(hostname: string, scUrl: string): Promise<any> {
let graphQuery;
if (scUrl !== '' && scUrl.indexOf('sites') !== -1) {
// query just a regular sub site collection
graphQuery = `beta/sites/${hostname}:${scUrl}`;
} else if (scUrl !== '' && scUrl.indexOf('sites') === -1) {
// query just a regular sub site collection
graphQuery = `beta/sites/${hostname}/sites/`;
} else {
// query only the root
graphQuery = `beta/sites/${hostname}`;
}
console.log(graphQuery, scUrl);
return this._graphClient.get(
graphQuery,
GraphHttpClient.configurations.v1
).then(
(response: HttpClientResponse) => {
return response.json();
}
).catch(
(error) => {
throw error;
}
);
}
/**
* Graph query that returns all lists in a specific web
* @param siteId
* @param url
*/
private _evaluateLists(siteId: string, url: string): Promise<any> {
// Transfer result values to the group variable
// TODO: Check until you find the final subsite
const NO_RESULT = 'No document library could be found under the give path';
let pathToFileQuery = `beta/sites/${siteId}/Lists`;
return this._graphClient.get(
pathToFileQuery,
GraphHttpClient.configurations.v1
).then(
(response) => {
return response.json();
}
)
}
/**
* Evaluate if site collection exists and return it if found
* @param url
*/
public EvaluateSiteCollection(url: string): Promise<any> {
let scUrl;
// General url evaluation
try {
this._urlToEvaluate = this._evaluateUrl(url);
} catch (Exception) {
throw Exception;
}
// Try to make site collection url
try {
scUrl = this._getSiteCollectionUrl(this._urlToEvaluate.pathname);
} catch (Exception) {
throw Exception
}
// if building a site collection url worked well
if (scUrl !== null && scUrl !== undefined) {
return this._evaluateWeb(this._urlToEvaluate.hostname, scUrl)
.then(
(response) => {
return response;
}
)
.catch(
(error) => {
throw `Error retrieving Site Collection at ${scUrl} - ${error}`;
}
)
}
}
/**
* Evaluate a web by URL and returns the web object
* @param url
*/
public EvaluateWeb(url: string): Promise<any> {
let scUrl;
// General url evaluation
try {
this._urlToEvaluate = this._evaluateUrl(url);
} catch (Exception) {
throw Exception;
}
// Try to make web url
try {
scUrl = this._getAssumedWeburl(this._urlToEvaluate.pathname);
} catch (Exception) {
console.log('Error: Identify Site Collection URL');
throw Exception
}
if (scUrl !== null && scUrl !== undefined) {
return this._evaluateWeb(this._urlToEvaluate.hostname, scUrl)
.then(
(response) => {
return response;
}
)
.catch(
(error) => {
throw `Error retrieving Site Collection at ${scUrl} - ${error}`;
}
)
}
}
/**
* Evaluate if web and a specific list exists in the web
* @param url
* @param webid
*/
public EvaluateList(url: string): Promise<any> {
let webUrl,
listUrl;
// General url evaluation
try {
this._urlToEvaluate = this._evaluateUrl(url);
} catch (Exception) {
throw Exception;
}
// Try to make web url url
try {
webUrl = this._getAssumedWeburl(this._urlToEvaluate.pathname);
} catch (Exception) {
throw Exception
}
// try to find a list or document library url
try {
listUrl = this._getAssumedList(this._urlToEvaluate.pathname);
} catch (Exception) {
throw Exception
}
// If list and web are ok proceed
if (webUrl !== null && webUrl !== undefined &&
listUrl !== null && listUrl !== undefined) {
/**
* Evaluate web because the graph ID is needed to evaluate a list
*/
return this._evaluateWeb(this._urlToEvaluate.hostname, webUrl)
.then(
(response) => {
let webIdResults,
webId;
// just in case multiple items got returned by the graph
if (response.value !== undefined) {
// filter the best match
webIdResults = response.value.filter((obj) => {
return obj.webUrl.toLowerCase().indexOf(webUrl) !== -1;
});
// return first found id
webId = webIdResults[0].id;
} else {
// if only single item was returned
webId = response.id;
}
return this._evaluateLists(webId, listUrl)
.then(
(response) => {
/**
* Graph always returns all lists and docuemnt libraries from site collection
* This filters out to return only the searched List or library instead of all
* In case none could be found only a empty array will get returned
*/
const suiteableLists = response.value.filter((obj) => {
return obj.webUrl.toLowerCase().indexOf(listUrl) !== -1;
});
response.value = suiteableLists;
return response;
}
)
.catch(
(error) => {
throw `List cannot be found or evaluated - ${error}`;
}
)
}
)
.catch(
(error) => {
throw `Error retrieving Site Collection at ${webUrl} - ${error}`;
}
)
}
}
}

View File

@ -0,0 +1,32 @@
import * as React from 'react';
export interface IGraphEvalDebugState {
panelText: string;
}
export interface IGraphEvalDebugProps {
panelText: string;
}
export default class GraphEvalDebug extends React.Component<IGraphEvalDebugProps, IGraphEvalDebugState> {
constructor(props) {
super(props);
}
public render(): React.ReactElement<void> {
return (
<div>
<label>
<strong>Debugging Information</strong>
</label>
<pre className="dbgInfo">{this.props.panelText}</pre>
</div>
)
};
}

View File

@ -0,0 +1,21 @@
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.graphEvalUrl {
.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);
}
}
:global {
.dbgInfo {
background-color: whitesmoke;
display: block;
padding: 0.5em 0.25em;
overflow: auto;
box-sizing: border-box;
min-height: 0px;
transition: height 1s ease-in-out;
margin-top: 1em;
}
}

View File

@ -0,0 +1,237 @@
import * as React from 'react';
import styles from './GraphEvalUrl.module.scss';
import { IGraphEvalUrlProps } from './IGraphEvalUrlProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { GraphHttpClient } from '@microsoft/sp-http';
import GraphEvalClient from './GraphEvalClient';
// Office UI Fabric Imports
import {
TextField
} from 'office-ui-fabric-react/lib/TextField';
import GraphEvalDebug from './GraphEvalDebug'
export interface IGraphEvalUrlState {
debugMessage: string
};
export default class GraphEvalUrl extends React.Component<IGraphEvalUrlProps, {}> {
_graphClient: GraphHttpClient
state: IGraphEvalUrlState;
constructor(props) {
super(props);
this._graphClient = props.graphClient;
this.state = {
debugMessage: ''
}
}
/**
* Catches all Graph Client errors and print it in debug console
* @param errors
*/
private _catchErrors(errors: string) {
this.setState(
{
debugMessage: errors
}
)
}
/**
* Clear all debug messages
*/
private _cleanDebug() {
this.setState(
{
debugMessage: ''
}
)
}
/**
* Evaluate a site collection on blur
* @param event
*/
private _evaluateSiteCollection(event) {
// get value of current input
let currentUrlValue = event.target.value;
if(currentUrlValue === ""){
this._catchErrors('No URL specified')
return;
}
// create new graph evaluation client aka a validator
let graphEval = new GraphEvalClient(this._graphClient);
// request site collection from the Microsoft Graph
graphEval.EvaluateSiteCollection(currentUrlValue)
.then(
(response) => {
this.setState({
debugMessage: 'Found Site Collection:\n\n' + JSON.stringify(response, null, 2)
})
}
)
.catch(this._catchErrors);
}
/**
* Evaluate a site collection and web
* @param event
*/
private _evaluateWeb(event) {
// get value of current input
let currentUrlValue = event.target.value;
// create new graph evaluation client aka a validator
let graphEval = new GraphEvalClient(this._graphClient);
if(currentUrlValue === ""){
this._catchErrors('No URL specified')
return;
}
// request site collection from the Microsoft Graph
graphEval.EvaluateWeb(currentUrlValue)
.then(
(response) => {
this.setState({
debugMessage: 'Site Collection found:\n'
+ JSON.stringify(response, null, 2)
+ '\nTry to evaluate web next:\n\n'
})
// then try to the get web
graphEval.EvaluateWeb(currentUrlValue)
.then(
(response) => {
this.setState({
debugMessage: 'Web found:\n'
+ JSON.stringify(response, null, 2)
});
}
).catch(this._catchErrors);
}
)
.catch(this._catchErrors);
}
/**
* Evaluate if a list exists in a particulare web site
* @param event
*/
private _evaluateList(event) {
// get value of current input
let currentUrlValue = event.target.value;
if(currentUrlValue === ""){
this._catchErrors('No URL specified')
return;
}
// create new graph evaluation client aka a validator
let graphEval = new GraphEvalClient(this._graphClient);
// then try to the get web
graphEval.EvaluateList(currentUrlValue)
.then(
(response) => {
if (response.value !== null && response.value.length !== 0) {
this.setState({
debugMessage: '\nList found:\n'
+ JSON.stringify(response, null, 2)
});
} else {
this.setState({
debugMessage: '\nNo valid list could be found:\n'
+ JSON.stringify(response, null, 2)
});
}
}
).catch((error) => {
this.setState({
debugMessage: error
})
})
}
/**
* Renders demo web part to evaluate three different variants using Microsoft Graph
*/
public render(): React.ReactElement<IGraphEvalUrlProps> {
return (
<div>
<h2>SharePoint URL Input validation using Microsoft Graph</h2>
<p>Enter a url to site collection, web or list below. Press <kbd>Tab</kbd> to start evaluation.
Once the evaluation of any of the specific text field is completed the debugging information
the information returned by the graph or displays the error message.
</p>
{/* Evaluates the inpurt on tab leave and try to find a site collection base in url */}
<TextField
name='scInput'
id='scInput'
label='Site Collection Evaluation'
onBlur={this._evaluateSiteCollection.bind(this)}
/>
{/* Evaluates the inpurt on tab leave and try to find
a site collection and corresponding web based on url base in url */}
<TextField
name='webInput'
id='webInput'
label='Web Evaluation'
onBlur={this._evaluateWeb.bind(this)}
/>
{/* Evaluates the inpurt on tab leave and try to find
corresponding web and list based on url base in url */}
<TextField
name='listInput'
id='listInput'
prefix='https://'
label='List Evaluation'
onBlur={this._evaluateList.bind(this)}
/>
<br />
{/* Displays Graph Debugging information */}
<GraphEvalDebug panelText={this.state.debugMessage} />
{/* Dummy container to make sure CSS got rendered */}
<div className={styles.container} />
</div >
);
}
}

View File

@ -0,0 +1,6 @@
import { GraphHttpClient } from "@microsoft/sp-http";
export interface IGraphEvalUrlProps {
description: string;
graphClient: GraphHttpClient
}

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 IGraphEvalUrlWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
}
declare module 'GraphEvalUrlWebPartStrings' {
const strings: IGraphEvalUrlWebPartStrings;
export = strings;
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
]
}
}