Merge branch 'dev' of https://github.com/SharePoint/sp-dev-fx-webparts into dev
This commit is contained in:
commit
386fcabb75
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Summary
|
||||
|
||||
Sample Angular application before and after migration to a SharePoint Framework client-side web part.
|
||||
This is a sample Angular application before and after it has been migrated to a SharePoint Framework client-side web part.
|
||||
|
||||
Application before migration:
|
||||
![Angular todo application](./assets/angular-todo-preview.png)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Most Popular Items WebPart using Angular & ngOfficeUIFabric
|
||||
# Most Popular Items WebPart using Angular & ngOfficeUIFabric
|
||||
|
||||
## Summary
|
||||
|
||||
This Web Part displays the Most Popular Items from the given Site/Document Library URL using search API.
|
||||
This web part displays the most popular items from a given site and document library URL using the SahrePoint search API.
|
||||
|
||||
![Most Popular Items WebPart built using Angular and ngOfficeUIFabric](./assets/preview.png)
|
||||
|
||||
|
@ -41,16 +41,16 @@ Version|Date|Comments
|
|||
|
||||
## Features
|
||||
|
||||
The Most Popular Items is a sample Client-Side Web Part built on the SharePoint Framework built using Angular and ngOfficeUIFabric.
|
||||
The Most Popular Items web part is a sample client-side web part built on the SharePoint Framework built using Angular and ngOfficeUIFabric.
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
This web part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
- using Angular for building SharePoint Framework Client-Side Web Parts
|
||||
- using ngOfficeUIFabric for styling Angular Client-Side Web Parts
|
||||
- including Angular and ngOfficeUIFabric in the Web Part bundle
|
||||
- using a newer version of ngOfficeUIFabric for styling Client-Side Web Parts
|
||||
- using non-reactive Web Part Property Pane and custom Properties
|
||||
- using conditional rendering for one-time Web Part setup
|
||||
- passing Web Part configuration to Angular and reacting to configuration changes
|
||||
- using Angular for building SharePoint Framework client-side web parts
|
||||
- using ngOfficeUIFabric for styling Angular client-side web parts
|
||||
- including Angular and ngOfficeUIFabric in the web part bundle
|
||||
- using a newer version of ngOfficeUIFabric for styling client-side web parts
|
||||
- using non-reactive web part property pane and custom properties
|
||||
- using conditional rendering for one-time web part setup
|
||||
- passing web part configuration to Angular and reacting to configuration changes
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/angular-mostpopularitems" />
|
|
@ -1,9 +1,9 @@
|
|||
## Angular MS Graph Web Part Built with Angular v1.x
|
||||
## Angular MS Graph Web Part Built with Angular v1.x
|
||||
|
||||
## Summary
|
||||
Sample MS Graph Web Part that connects to the Microsoft Graph and pull SharePoint information from your
|
||||
tenant. It will first pull the Root Site Collection (currently a limitation by Microsoft Graph). Then will
|
||||
display all the Lists associated with the site. Then all the items inside the List.
|
||||
This is a sample MS Graph web part that connects to Microsoft Graph and pulls SharePoint information from your
|
||||
tenant. It will first pull the root site collection (currently a limitation by Microsoft Graph), then it will
|
||||
display all the lists associated with the site followed by all the items inside the list.
|
||||
|
||||
![First Screen](./assets/Connect.png)
|
||||
|
||||
|
@ -16,7 +16,7 @@ display all the Lists associated with the site. Then all the items inside the Li
|
|||
![Announcement List Items](./assets/Items.png)
|
||||
|
||||
|
||||
> Note: I currently only have models developed for the Announcements List. All other lists will currently generate errors.
|
||||
> Note: I currently only have models developed for the Announcements list. All other lists will currently generate errors.
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-ga-green.svg)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# Angular multi-page client-side web part
|
||||
# Angular multi-page client-side web part
|
||||
|
||||
## Summary
|
||||
|
||||
Sample SharePoint Framework client-side web parts built using Angular illustrating building multi-page web parts.
|
||||
This is a sample SharePoint Framework client-side web part built using Angular, illustrating building multi-page web parts.
|
||||
|
||||
### Poll
|
||||
|
||||
Sample poll web part allowing users to vote and view the results.
|
||||
This sample contains a poll web part allowing users to vote and view the results.
|
||||
|
||||
![Poll web part built on the SharePoint Framework using Angular](./assets/poll-preview.gif)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ File Update/Delete webpart using AngularJs and ngOfficeUIFabric with the SharePo
|
|||
|
||||
Edit webpart properties to set Document library Name. Initially, It has been set to `Documents`.
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/version-GA-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# Angular & ngOfficeUIFabric Client-Side Web Part
|
||||
|
||||
## Summary
|
||||
|
||||
this is a sample web part that illustrates the use of Angular and [ngOfficeUIFabric](http://ngofficeuifabric.com/) with the SharePoint Framework.
|
||||
You can find a video recording walk-through this sample from [SharePoint PnP YouTube channel](https://www.youtube.com/watch?v=FS-_0KENJkI).
|
||||
|
||||
![Sample To do SharePoint Framework Client-Side Web Part built using Angular and ngOfficeUIFabric](./assets/preview.png)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-drop2-red.svg)
|
||||
|
||||
## 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)
|
||||
--------|---------
|
||||
angular-ngofficeuifabric-todo|Waldek Mastykarz (MVP, Rencore, @waldekm)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.1|September 9, 2016|Updated sample to SPFx v0.2.0 and changed to loading Angular and ngOfficeUIFabric from CDN
|
||||
1.0|August 29, 2016|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
|
||||
- in the command line run:
|
||||
- `npm i`
|
||||
- `tsd install`
|
||||
- `gulp serve`
|
||||
|
||||
## Features
|
||||
|
||||
The To Do web part is a sample client-side web part built on the SharePoint Framework built using Angular and ngOfficeUIFabric.
|
||||
|
||||
This web part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
- using Angular v1.x with TypeScript for building SharePoint Framework client-side web parts
|
||||
- using ngOfficeUIFabric for styling Angular v1.x client-side web parts
|
||||
- including Angular and ngOfficeUIFabric in the web part bundle
|
||||
- using a newer version of Office UI Fabric for styling client-side web parts
|
||||
- loading CSS stylesheets from a CDN
|
||||
- using non-reactive web part property pane
|
||||
- using conditional rendering for one-time web part setup
|
||||
- passing web part configuration to Angular and reacting to configuration changes
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/angular-ngofficeuifabric-todo" />
|
|
@ -1,10 +1,10 @@
|
|||
# Search Client-Side Web Part Built with Angular v1.x
|
||||
# Search Client-Side Web Part Built with Angular v1.x
|
||||
|
||||
## Summary
|
||||
Sample Search Web Part that illustrates how you can use Angular within the new SharePoint Framework
|
||||
This is a sample search web part that illustrates how you can use Angular within the new SharePoint Framework
|
||||
|
||||
![Sample of the search web part](./assets/angularSearch.png)
|
||||
This app uses SharePoint's Search REST API endpoint to query listitems of a specific content type and displays the results to the end user.
|
||||
This app uses the SharePoint Search REST API endpoint to query listitems of a specific content type and displays the results to the end user.
|
||||
Ideally instead of selecting a content type for the search you would want to select a Result Source, but currently Result Sources are not
|
||||
available through SharePoint's REST API.
|
||||
|
||||
|
@ -52,9 +52,9 @@ Version|Date|Comments
|
|||
- Publishing features on site collection
|
||||
- Publishing features on site
|
||||
|
||||
> Note: The Content Types that I pull for the search come from the Publishing Content Type which only
|
||||
> Note: The content types that are pulled by the search come from the publishing content type which are only
|
||||
> available when the Publishing Features are enabled on the site. I'm also searching by content type name
|
||||
> and not by id becauase then I would get everything that inherits from that content type. I only want the
|
||||
> and not by id because then I would get everything that inherits from that content type. I only want the
|
||||
> the results for a specific content type and not everything that inherits that content type as well
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/angular-search" />
|
|
@ -1,4 +1,4 @@
|
|||
import { ISPCType } from './AngularSearchWebPart'
|
||||
import { ISPCType } from './AngularSearchWebPart';
|
||||
|
||||
export default class MockHttpClient {
|
||||
private static _items: ISPCType[] = [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ISearchResults } from './../models/ISearchResults'
|
||||
import { ISearchResults } from './../models/ISearchResults';
|
||||
|
||||
export interface IDataService {
|
||||
getSearchResults(webUrl: string, contentType: string): angular.IPromise<ISearchResults>;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Angular2 Web Part Prototype
|
||||
# Angular2 Web Part Prototype
|
||||
|
||||
## Note to developers
|
||||
> This web part sample is currently in prototype phase and subject to change.
|
||||
This sample is not currently supported for use in production enviornments as unexpected behavior may occur.
|
||||
This sample is not currently supported for use in production environments as unexpected behavior may occur.
|
||||
It is provided as guidance for building Angular2 web parts in the SharePoint Framework environment.
|
||||
This sample is a work in progress and it will be updated as advances in stability are made.
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Using jQuery loaded from CDN
|
||||
# Using jQuery loaded from CDN
|
||||
|
||||
## Summary
|
||||
|
||||
Sample Web Parts illustrating using jQuery and its plugins loaded from CDN for building SharePoint Framework Client-Side Web Parts.
|
||||
This is a sample web Part that illustrates the use of jQuery and its plugins loaded from CDN for building SharePoint Framework client-side web parts.
|
||||
|
||||
![Sample Web Part built using jQuery showing current weather in the specified location](./assets/preview_weather.png)
|
||||
|
||||
|
@ -40,12 +40,12 @@ Version|Date|Comments
|
|||
|
||||
## Features
|
||||
|
||||
This project contains sample Client-Side Web Parts built on the SharePoint Framework illustrating how to use jQuery and its plugins loaded from CDN for building SharePoint Framework Client-Side Web Parts.
|
||||
This project contains sample client-side web parts built on the SharePoint Framework illustrating how to use jQuery and its plugins loaded from CDN for building SharePoint Framework client-side web parts.
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
This web part illustrates the following concepts on top of the SharePoint Framework:
|
||||
- loading jQuery from CDN
|
||||
- loading non-AMD jQuery plugins with configured dependency on jQuery
|
||||
- using non-reactive Web Part Property Pane
|
||||
- using conditional rendering for one-time Web Part setup
|
||||
- using non-reactive web part Property Pane
|
||||
- using conditional rendering for one-time web part setup
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/jquery-cdn" />
|
|
@ -1,18 +1,18 @@
|
|||
# JQuery, Photopile.JS & Office UI Fabric Client-Side Web Part
|
||||
# JQuery, Photopile.JS & Office UI Fabric Client-Side Web Part
|
||||
|
||||
## Summary
|
||||
|
||||
Sample Web Part illustrating using JQuery and [Photopile.Js](https://github.com/bigbhowell/Photopile-JS)
|
||||
This is a sample web part that illustrated the use of JQuery and [Photopile.Js](https://github.com/bigbhowell/Photopile-JS)
|
||||
with the SharePoint Framework.
|
||||
|
||||
With it, you can display the photos contained in a SharePoint Pictures Library and it
|
||||
With this web part you can display the photos contained in a SharePoint pictures library and it
|
||||
simulates a pile of photos scattered about on a surface. Thumbnail clicks remove photos from the pile,
|
||||
(enlarging them as if being picked up by the user), and once in view a secondary click returns the photo to the pile.
|
||||
(enlarging them as if being picked up by the user) and once in view a second click returns the photo to the pile.
|
||||
|
||||
![Photopile Web Part displayed in SharePoint Workbench](./assets/photopileoverview.gif)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-ga-green.svg)
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-drop1-red.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
|
@ -23,14 +23,13 @@ simulates a pile of photos scattered about on a surface. Thumbnail clicks remove
|
|||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
jquery-photopile|Olivier Carpentier (@olivierc) , Gautam Sheth(SharePoint Consultant,Rapid Circle,@gautamdsheth)
|
||||
jquery-photopile|Olivier Carpentier (@olivierc)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|September 9, 2016|Initial release
|
||||
2.0|May 26, 2017|GA 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.**
|
||||
|
@ -51,12 +50,12 @@ This web part uses React, Office UI Fabric, JQuery, JQuery UI and Photopile.js.
|
|||
and French (fr-fr).
|
||||
|
||||
It is able to:
|
||||
* List Picture Libs contained in the current SharePoint web site
|
||||
* List picture libraries contained in the current SharePoint web site
|
||||
* List all the pictures in the selected List
|
||||
* Render the pics as a cool photopile
|
||||
* Render the pictures as a cool photopile
|
||||
* Personalize the layout thanks to editable settings
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
This web part illustrates the following concepts on top of the SharePoint Framework:
|
||||
* Include JQuery and external framework in your solution
|
||||
* Implement rich web part properties panel with controls like DropDown, Sliders, Toggle, etc.
|
||||
* Load dynamic data from SharePoint as web part properties
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Display List JavaScript Client-Side Web Part
|
||||
# Display List JavaScript Client-Side Web Part
|
||||
|
||||
## Summary
|
||||
Simplistic sample Web Part that demonstrates the use of JavaScript in creating a SharePoint Framework web part. The properties pane for this web part display a drop down list of lists in the current web. Once the user selects one of the lists, the web part display the contents of the list.
|
||||
This simplistic sample Web Part demonstrates the use of JavaScript in a SharePoint Framework web part. The properties pane for this web part display a drop down list of lists in the current web. Once the user selects one of the lists, the web part display the contents of the list.
|
||||
|
||||
|
||||
![Screeshot of the Display List web part](./assets/display-list-preview.png).
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Embed a PowerBI report in a Client-Side Web Part
|
||||
# Embed a PowerBI report in a Client-Side Web Part
|
||||
|
||||
## Summary
|
||||
|
||||
Sample SharePoint Framework Client-Side Web Part embedding a PowerBI report using PowerBI Embedded without any server-side code.
|
||||
This sample SharePoint Framework client-side web part embedding a PowerBI report using PowerBI Embedded without any server-side code.
|
||||
|
||||
![PowerBI Embedded Client-SideWeb Part in the SharePoint Workbench](./assets/screenshot_powerbi_embedded_spfx.png)
|
||||
|
||||
|
|
|
@ -3,9 +3,6 @@ logs
|
|||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Yeoman configuration files
|
||||
.yo-rc.json
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
|
@ -14,7 +11,7 @@ dist
|
|||
lib
|
||||
solution
|
||||
temp
|
||||
*.spapp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
|
@ -2,7 +2,7 @@
|
|||
.vscode
|
||||
coverage
|
||||
node_modules
|
||||
solution
|
||||
sharepoint
|
||||
src
|
||||
temp
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.1.1",
|
||||
"libraryName": "react-app-settings",
|
||||
"libraryId": "9573efb7-06d1-4134-aa8d-f6b4803d6096",
|
||||
"environment": "spo"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
# SPFx React app settings webpart #
|
||||
|
||||
## Summary
|
||||
|
||||
This sample shows how appSettings.json file can be added and used within SharePoint Framewrok webparts similar to the Web.config / App.config key value app settings in .NET Framework projects.
|
||||
That allows better DevOps and Continious Integration automation. Typescript module appSettings.d.ts is also added so it allows the json app settings to be imported to any webpart or react component with intellisense support.
|
||||
|
||||
![SPFx React app settings webpart](./assets/spfx-appSettings-json.PNG)
|
||||
|
||||
### Easy to replace values in appSettings.json if DEV, QA, PROD environments.
|
||||
|
||||
Since the appSettings.json is a known format, a DevOps guy can easily open it and add values according the environment then start `gulp build` process in an CI tool like VSTS, Jenkins.
|
||||
|
||||
### Gulp task added to verity that the appSettings.json and appSettings.d.ts match.
|
||||
|
||||
I have added appSettingsGulp.js with one gulp task in it. The task starts just before solution build or on watch to verify that all the app settings match in both appSettings.json and appSettings.d.ts. If they not match, then error is thrown so the CI tool is aware that the build failed.
|
||||
|
||||
### Keep the appSettings.json and appSettings.d.ts format as is.
|
||||
|
||||
Since the gulp task I created contains checks based on string operations, it is required that the appSettings.json and appSettings.d.ts are in format as provided and just key-pairs are added to the json file and respective just new properties are added to the IAppSettings interface in the appSettings.d.ts.
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-GA-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)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Office 365 subscription with SharePoint Online.
|
||||
- SharePoint Framework [development environment](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment) already set up.
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-app-settings | Velin Georgiev ([@VelinGeorgiev](https://twitter.com/velingeorgiev))
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
0.0.1|August 03, 2017 | Initial commit
|
||||
|
||||
## 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 repository.
|
||||
- Open the command line, navigate to the web part folder and execute:
|
||||
- `npm i`
|
||||
- `gulp serve`
|
||||
- Navigate to the local or hosted version of the SharePoint workbench.(`https://<your_tenant>.sharepoint.com/sites/<your_site>/_layouts/15/workbench.aspx`).
|
||||
- Add the **React AppSettings Webpart** web part.
|
||||
|
||||
## Features
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
- Using React for building SharePoint Framework client-side web parts.
|
||||
- The use of app settings and passing the app settings to React components.
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-app-settings" />
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"entries": [
|
||||
{
|
||||
"entry": "./lib/webparts/reactAppSettings/ReactAppSettingsWebPart.js",
|
||||
"manifest": "./src/webparts/reactAppSettings/ReactAppSettingsWebPart.manifest.json",
|
||||
"outputPath": "./dist/react-app-settings.bundle.js"
|
||||
}
|
||||
],
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"reactAppSettingsStrings": "webparts/reactAppSettings/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "todo-webpart-sample",
|
||||
"container": "react-app-settings",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"solution": {
|
||||
"name": "react-app-settings-client-side-solution",
|
||||
"id": "9573efb7-06d1-4134-aa8d-f6b4803d6096",
|
||||
"version": "1.0.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-app-settings.sppkg"
|
||||
}
|
||||
}
|
|
@ -16,13 +16,11 @@
|
|||
"export-name": false,
|
||||
"forin": false,
|
||||
"label-position": false,
|
||||
"label-undefined": false,
|
||||
"member-access": true,
|
||||
"no-arg": false,
|
||||
"no-console": false,
|
||||
"no-construct": false,
|
||||
"no-duplicate-case": true,
|
||||
"no-duplicate-key": false,
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": false,
|
||||
"no-function-expression": true,
|
||||
|
@ -32,8 +30,6 @@
|
|||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-unused-imports": true,
|
||||
"no-unused-variable": true,
|
||||
"no-unreachable": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
|
@ -43,9 +39,7 @@
|
|||
"use-named-parameter": true,
|
||||
"valid-typeof": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false,
|
||||
"prefer-const": true,
|
||||
"a11y-role": true
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
const gulp = require('gulp');
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
|
||||
/**
|
||||
* Checks if the app settings match in both the appSettings.json and appSettings.d.ts.
|
||||
*/
|
||||
const verifyAppSettings = require('./src/appSettingsGulp.js');
|
||||
build.rig.addBuildTasks(verifyAppSettings);
|
||||
|
||||
build.initialize(gulp);
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "react-app-settings",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "~1.1.0",
|
||||
"@microsoft/sp-webpart-base": "~1.1.1",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"react": "15.4.2",
|
||||
"react-dom": "15.4.2",
|
||||
"@types/react": "0.14.46",
|
||||
"@types/react-dom": "0.14.18",
|
||||
"@types/react-addons-shallow-compare": "0.14.17",
|
||||
"@types/react-addons-update": "0.14.14",
|
||||
"@types/react-addons-test-utils": "0.14.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.1.0",
|
||||
"@microsoft/sp-module-interfaces": "~1.1.0",
|
||||
"@microsoft/sp-webpart-workbench": "~1.1.0",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
declare interface IAppSettings {
|
||||
tenantUrl: string;
|
||||
assetsUrl: string;
|
||||
webSearchUrl: string;
|
||||
}
|
||||
|
||||
declare module 'appSettings' {
|
||||
const appSettings: IAppSettings;
|
||||
export = appSettings;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"tenantUrl": "https://contoso.sharepoint.com/",
|
||||
"assetsUrl": "https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/4.1.0/css/fabric.min.css",
|
||||
"webSearchUrl": "https://www.bing.com/cr?IG=C027D8AA145E4C698CBAC863891F7ADF&CID=35725CD571236AE21C6D560670856B67&rd=1&h=Uonuek4ZZjPKBTXFL2TqY-P-mH_lVRUJpYqKN5gF-Qk&v=1&r=https%3a%2f%2fwww.bing.com%2fsearch%3fq%3dvelin%2bgeorgiev%2bblog&p=DevEx,5294.1"
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
'use strict';
|
||||
var fs = require('fs'),
|
||||
build = require('@microsoft/sp-build-web');
|
||||
|
||||
/**
|
||||
* Verifies if the appSettings.json and appSettings.d.ts are have the same appSetting keys.
|
||||
*/
|
||||
var verifyAppSettings = build.subTask('verify-app-settings', function(gulp, buildConfig, done) {
|
||||
|
||||
// will hold the keys from the appSettings.json file.
|
||||
var appSettingsJsKeys = [];
|
||||
|
||||
// will hold the keys from the appSettings.d.ts file.
|
||||
var appSettingsTsKeys = [];
|
||||
|
||||
/**
|
||||
* Get all appSettings keys from the appSettings.d.ts text in javascript/nodejs array.
|
||||
* Pure string operations.
|
||||
*/
|
||||
var getappSettingsTsKeys = function(appSettingsTsSettingsAsText, appSettingsTsKeysArray) {
|
||||
|
||||
var keyEndPos = appSettingsTsSettingsAsText.indexOf(":");
|
||||
|
||||
// end the recursion if no more `:`.
|
||||
if(keyEndPos === -1) return appSettingsTsKeysArray;
|
||||
|
||||
// substring the appSetting key from the text.
|
||||
var key = appSettingsTsSettingsAsText.substring(0, keyEndPos);
|
||||
|
||||
// add the appSetting key to the result array.
|
||||
appSettingsTsKeysArray.push(key);
|
||||
|
||||
// exclude the key for the next call.
|
||||
appSettingsTsSettingsAsText = appSettingsTsSettingsAsText.substring(appSettingsTsSettingsAsText.indexOf(";") + 1);
|
||||
|
||||
// call again for the next key.
|
||||
getappSettingsTsKeys(appSettingsTsSettingsAsText, appSettingsTsKeysArray);
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
/**
|
||||
* Opens the appSettings.json file and pulls the appSetting keys in javascript array.
|
||||
* Then calls operations on appSettings.d.ts.
|
||||
*/
|
||||
fs.readFile('./src/appSettings.json', 'utf8', function (err,data) {
|
||||
if (err) { return reject(err); }
|
||||
|
||||
// remove some strings so we can parse to JSON, prue string manipulation.
|
||||
var jsonAsString = data.replace(/(?:\r\n|\r|\n)/g, "").trim();
|
||||
|
||||
// appSettings.json keys to array.
|
||||
appSettingsJsKeys = Object.keys(JSON.parse(jsonAsString));
|
||||
|
||||
/**
|
||||
* Opens the appSettings.d.ts file and pulls the appSetting keys in javascript array.
|
||||
* Then compares the appSettings.d.ts and the appSettings.json keys.
|
||||
*/
|
||||
return fs.readFile('./src/appSettings.d.ts', 'utf8', function (err,data) {
|
||||
if (err) { return reject(err); }
|
||||
|
||||
// remove some strings, prue string manipulation.
|
||||
var text = data.substring(data.indexOf("{") + 1, data.indexOf("}")).replace(/ /g,"").replace(/(?:\r\n|\r|\n)/g, "").trim();
|
||||
|
||||
// fill the appSettingsTsKeys array with the appSettings.d.ts keys.
|
||||
getappSettingsTsKeys(text, appSettingsTsKeys);
|
||||
|
||||
// now we have two arrays with keys to compare.
|
||||
|
||||
// checks the appSettings.json for missing keys.
|
||||
var l = appSettingsTsKeys.length;
|
||||
while(l--) {
|
||||
|
||||
if(appSettingsJsKeys.indexOf(appSettingsTsKeys[l]) === -1)
|
||||
{
|
||||
build.error(`Key \"${appSettingsTsKeys[l]}\" not found in appSettings.json, but exists in appSettings.d.ts. Please fix your appSettings.`);
|
||||
return reject();
|
||||
}
|
||||
}
|
||||
|
||||
// checks the appSettings.d.ts for missing keys.
|
||||
l = appSettingsJsKeys.length;
|
||||
while(l--) {
|
||||
|
||||
if(appSettingsTsKeys.indexOf(appSettingsJsKeys[l]) === -1)
|
||||
{
|
||||
build.error(`Key \"${appSettingsJsKeys[l]}\" not found in appSettings.d.ts, but exists in appSettings.json. Please fix your appSettings.`);
|
||||
return reject();
|
||||
}
|
||||
}
|
||||
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
exports.default = verifyAppSettings;
|
|
@ -0,0 +1,3 @@
|
|||
export interface IReactAppSettingsWebPartProps {
|
||||
description: string;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||
|
||||
"id": "4c2bfa08-5735-4af9-ae2f-de0b1a9dfe7d",
|
||||
"alias": "ReactAppSettingsWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "*", // The "*" signifies that the version should be taken from the package.json
|
||||
"manifestVersion": 2,
|
||||
|
||||
/**
|
||||
* This property should only be set to true if it is certain that the webpart does not
|
||||
* allow arbitrary scripts to be called
|
||||
*/
|
||||
"safeWithCustomScriptDisabled": false,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "4c2bfa08-5735-4af9-ae2f-de0b1a9dfe7d",
|
||||
"group": { "default": "Under Development" },
|
||||
"title": { "default": "ReactAppSettings" },
|
||||
"description": { "default": "Shows how settings can be stored in appSettings.json file so they can easly be maintained for different envoirements like QEV, QA, STAGE, PROD" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "ReactAppSettings"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
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 'reactAppSettingsStrings';
|
||||
import ReactAppSettings from './components/ReactAppSettings';
|
||||
import { IReactAppSettingsProps } from './components/IReactAppSettingsProps';
|
||||
import { IReactAppSettingsWebPartProps } from './IReactAppSettingsWebPartProps';
|
||||
|
||||
export default class ReactAppSettingsWebPart extends BaseClientSideWebPart<IReactAppSettingsWebPartProps> {
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IReactAppSettingsProps > = React.createElement(
|
||||
ReactAppSettings,
|
||||
{
|
||||
description: this.properties.description
|
||||
}
|
||||
);
|
||||
|
||||
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
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface IReactAppSettingsProps {
|
||||
description: string;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
.reactAppSettings {
|
||||
.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 {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.listItem {
|
||||
max-width: 715px;
|
||||
margin: 5px auto 5px auto;
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.button {
|
||||
// Our button
|
||||
text-decoration: none;
|
||||
height: 32px;
|
||||
|
||||
// Primary Button
|
||||
min-width: 80px;
|
||||
background-color: #0078d7;
|
||||
border-color: #0078d7;
|
||||
color: #ffffff;
|
||||
|
||||
// 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: 14px;
|
||||
font-weight: 400;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 0 16px;
|
||||
|
||||
.label {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 4px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import * as React from 'react';
|
||||
import styles from './ReactAppSettings.module.scss';
|
||||
import { IReactAppSettingsProps } from './IReactAppSettingsProps';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
|
||||
/**
|
||||
* Import the appSettings and use them to call apis.
|
||||
*/
|
||||
import * as appSettings from 'appSettings';
|
||||
|
||||
export default class ReactAppSettings extends React.Component<IReactAppSettingsProps, void> {
|
||||
public render(): React.ReactElement<IReactAppSettingsProps> {
|
||||
return (
|
||||
<div className={styles.reactAppSettings}>
|
||||
<div className={styles.container}>
|
||||
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
|
||||
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
|
||||
<span className="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
|
||||
<pre>
|
||||
appSettings.tenantUrl: {appSettings.tenantUrl}
|
||||
</pre>
|
||||
<pre>
|
||||
appSettings.assetsUrl: {appSettings.assetsUrl}
|
||||
</pre>
|
||||
<pre>
|
||||
appSettings.webSearchUrl: {appSettings.webSearchUrl}
|
||||
</pre>
|
||||
<p className="ms-font-l ms-fontColor-white">{escape(this.props.description)}</p>
|
||||
<a href="https://aka.ms/spfx" className={styles.button}>
|
||||
<span className={styles.label}>Learn more</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
declare interface IReactAppSettingsStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'reactAppSettingsStrings' {
|
||||
const strings: IReactAppSettingsStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/// <reference types="mocha" />
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
describe('ReactAppSettingsWebPart', () => {
|
||||
it('should do something', () => {
|
||||
assert.ok(true);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"es6-collections",
|
||||
"webpack-env"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Type definitions for Microsoft ODSP projects
|
||||
// Project: ODSP
|
||||
|
||||
/* Global definition for UNIT_TEST builds
|
||||
Code that is wrapped inside an if(UNIT_TEST) {...}
|
||||
block will not be included in the final bundle when the
|
||||
--ship flag is specified */
|
||||
declare const UNIT_TEST: boolean;
|
||||
|
||||
/* Global defintion for SPO builds */
|
||||
declare const DATACENTER: boolean;
|
|
@ -0,0 +1 @@
|
|||
/// <reference path="@ms/odsp.d.ts" />
|
|
@ -12,7 +12,7 @@ A simple Organisation Chart webpart using Office UI Fabric, React, REST API batc
|
|||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
|
||||
* [SharePoint Framework](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
|
||||
|
||||
|
||||
## Solution
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
* text=auto
|
|
@ -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
|
|
@ -0,0 +1,14 @@
|
|||
# Folders
|
||||
.vscode
|
||||
coverage
|
||||
node_modules
|
||||
sharepoint
|
||||
src
|
||||
temp
|
||||
|
||||
# Files
|
||||
*.csproj
|
||||
.git*
|
||||
.yo-rc.json
|
||||
gulpfile.js
|
||||
tsconfig.json
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.1.1",
|
||||
"libraryName": "react-pagecontributors",
|
||||
"libraryId": "1c18830a-4c18-4b82-a571-77863b19c66d",
|
||||
"environment": "spo"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
# Page Contributors Web Part
|
||||
|
||||
## Summary
|
||||
Displays page contributors in reverse chronological order.
|
||||
|
||||
![Organisation Chart for the current user running in SharePoint](./assets/pagecontributors_inaction.PNG)
|
||||
|
||||
![Organisation Chart for the current user running in local Workbench](./assets/pagecontributors_mockup.PNG)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/version-GA-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework](https:/dev.office.com/sharepoint)
|
||||
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
PnP-JS-Core
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
PageContributors | Stéphane Magne ([@SPParse](https://twitter.com/SPParse))
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|July 27, 2017|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 repository
|
||||
- in the command line run:
|
||||
- `npm install`
|
||||
- `gulp serve`
|
||||
|
||||
## Features
|
||||
|
||||
Settings :
|
||||
1. The maximum number of contributors to show
|
||||
2. The size of their icon
|
||||
3. A page URL to display contributors from an other page than the current one.
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
- Office UI Fabric
|
||||
- React
|
||||
- Pnp JS Core
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-pagecontributors" />
|
Binary file not shown.
After Width: | Height: | Size: 216 KiB |
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"entries": [
|
||||
{
|
||||
"entry": "./lib/webparts/pageContributors/PageContributorsWebPart.js",
|
||||
"manifest": "./src/webparts/pageContributors/PageContributorsWebPart.manifest.json",
|
||||
"outputPath": "./dist/page-contributors.bundle.js"
|
||||
}
|
||||
],
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"pageContributorsStrings": "webparts/pageContributors/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-pagecontributors",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"solution": {
|
||||
"name": "react-pagecontributors-client-side-solution",
|
||||
"id": "1c18830a-4c18-4b82-a571-77863b19c66d",
|
||||
"version": "1.0.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-pagecontributors.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"port": 4321,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"https": true,
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
// 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-unused-imports": 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "react-pagecontributors",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "~1.1.0",
|
||||
"@microsoft/sp-webpart-base": "~1.1.1",
|
||||
"@types/react": "0.14.46",
|
||||
"@types/react-addons-shallow-compare": "0.14.17",
|
||||
"@types/react-addons-test-utils": "0.14.15",
|
||||
"@types/react-addons-update": "0.14.14",
|
||||
"@types/react-dom": "0.14.18",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"react": "15.4.2",
|
||||
"react-dom": "15.4.2",
|
||||
"sp-pnp-js": "^2.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.1.0",
|
||||
"@microsoft/sp-module-interfaces": "~1.1.0",
|
||||
"@microsoft/sp-webpart-workbench": "~1.1.0",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import { PersonaSize } from "office-ui-fabric-react/lib/index";
|
||||
export interface IPageContributorsWebPartProps {
|
||||
personaSize: PersonaSize;
|
||||
numberOfFaces: number;
|
||||
pageUrl: string;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||
|
||||
"id": "dfb5229a-c1c3-4e98-870b-c40dd6e4ec4b",
|
||||
"alias": "PageContributorsWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "1.0.0",
|
||||
"manifestVersion": 2,
|
||||
"safeWithCustomScriptDisabled": false,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "dfb5229a-c1c3-4e98-870b-c40dd6e4ec4b",
|
||||
"group": { "default": "Under Development" },
|
||||
"title": { "default": "Page Contributors" },
|
||||
"description": { "default": "Displays page contributors in reverse chronological order" },
|
||||
"officeFabricIconFontName": "People",
|
||||
"properties": {
|
||||
"numberOfFaces": 5,
|
||||
"personaSize": 3
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneSlider,
|
||||
PropertyPaneDropdown,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
|
||||
import * as strings from 'pageContributorsStrings';
|
||||
import PageContributors from './components/PageContributors';
|
||||
import { IPageContributorsWebPartProps } from './IPageContributorsWebPartProps';
|
||||
import { PersonaSize } from "office-ui-fabric-react/lib/index";
|
||||
import pnp from 'sp-pnp-js';
|
||||
|
||||
export default class PagecontributionWebPart extends BaseClientSideWebPart<IPageContributorsWebPartProps> {
|
||||
public onInit(): Promise<void> {
|
||||
return super.onInit().then(_ => {
|
||||
pnp.setup({
|
||||
spfxContext: this.context
|
||||
});
|
||||
});
|
||||
}
|
||||
public render(): void {
|
||||
ReactDom.render(
|
||||
React.createElement(PageContributors, {
|
||||
personaSize: this.properties.personaSize,
|
||||
numberOfFaces: this.properties.numberOfFaces,
|
||||
pageUrl: this.properties.pageUrl
|
||||
})
|
||||
, this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.PropertyPaneBasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneSlider('numberOfFaces', {
|
||||
label: strings.PropertyPaneNbPersonasText,
|
||||
min: 1,
|
||||
max: 20
|
||||
}),
|
||||
PropertyPaneDropdown('personaSize', {
|
||||
label: strings.PropertyPanePersonaSizeText,
|
||||
options: [
|
||||
{ key: PersonaSize.tiny, text: strings.PropertyPaneIconsSizeTiny },
|
||||
{ key: PersonaSize.extraExtraSmall, text: strings.PropertyPaneIconsSizeEES },
|
||||
{ key: PersonaSize.extraSmall, text: strings.PropertyPaneIconsSizeES },
|
||||
{ key: PersonaSize.small, text: strings.PropertyPaneIconsSizeS },
|
||||
{ key: PersonaSize.regular, text: strings.PropertyPaneIconsSizeR },
|
||||
{ key: PersonaSize.large, text: strings.PropertyPaneIconsSizeL },
|
||||
{ key: PersonaSize.extraLarge, text: strings.PropertyPaneIconsSizeEL },
|
||||
],
|
||||
selectedKey: this.properties.personaSize
|
||||
}),
|
||||
PropertyPaneTextField('pageUrl',{
|
||||
label: strings.PropertyPanePageUrlText
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { PersonaSize } from "office-ui-fabric-react/lib";
|
||||
|
||||
export interface IPageContributorsProps {
|
||||
personaSize: PersonaSize;
|
||||
numberOfFaces: number;
|
||||
pageUrl: string;
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
import * as React from 'react';
|
||||
import * as strings from 'pageContributorsStrings';
|
||||
import { PersonaSize, IFacepileProps, Facepile, OverflowButtonType, Spinner, MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/index';
|
||||
import {
|
||||
Environment,
|
||||
EnvironmentType
|
||||
} from '@microsoft/sp-core-library';
|
||||
import pnp from 'sp-pnp-js';
|
||||
import { IPageContributorsProps } from "./IPageContributorsProps";
|
||||
|
||||
export class PageContributor {
|
||||
public displayName: string;
|
||||
public imageUrl: string;
|
||||
public constructor(userField) {
|
||||
this.displayName = userField.Title;
|
||||
this.imageUrl = `/_layouts/15/userphoto.aspx?size=M&accountname=${userField.Email}`;
|
||||
}
|
||||
}
|
||||
|
||||
function RemoveDuplicates(contributors: PageContributor[]): PageContributor[] {
|
||||
if (!contributors || !contributors.length)
|
||||
return [] as PageContributor[];
|
||||
|
||||
let results: PageContributor[] = [];
|
||||
contributors.forEach(contributor => {
|
||||
let alreadyExists = false;
|
||||
results.forEach(result => {
|
||||
if (result.displayName == contributor.displayName) {
|
||||
alreadyExists = true;
|
||||
}
|
||||
});
|
||||
if (!alreadyExists) {
|
||||
results.push(contributor);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
export class PageContributorsMockData {
|
||||
private static _items: PageContributor[] = [
|
||||
{ displayName: 'Stéphane Magne', imageUrl: null },
|
||||
{ displayName: 'Brangelina Pitt', imageUrl: null },
|
||||
{ displayName: 'Pika Chu', imageUrl: null },
|
||||
{ displayName: 'Rhino Faringite', imageUrl: null },
|
||||
{ displayName: 'Nobert Lenoir', imageUrl: null }
|
||||
];
|
||||
public static get(): Promise<PageContributor[]> {
|
||||
return new Promise<PageContributor[]>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(PageContributorsMockData._items);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class PageContributorsService {
|
||||
public static getPageContributors(pageServerRelativeUrl: string): Promise<PageContributor[]> {
|
||||
return new Promise<PageContributor[]>((resolve, reject) => {
|
||||
pnp.sp.web.getFileByServerRelativeUrl(pageServerRelativeUrl)
|
||||
.select('ModifiedBy')
|
||||
.expand('ModifiedBy')
|
||||
.get()
|
||||
.then(file => {
|
||||
pnp.sp.web.getFileByServerRelativeUrl(pageServerRelativeUrl)
|
||||
.versions
|
||||
.orderBy('Created')
|
||||
.select('ID, Created, CreatedBy')
|
||||
.expand('CreatedBy')
|
||||
.top(100)
|
||||
.get().then(versions => {
|
||||
let history = versions.map((version) => {
|
||||
return new PageContributor(version.CreatedBy);
|
||||
});
|
||||
history.unshift(new PageContributor(file.ModifiedBy));
|
||||
history = RemoveDuplicates(history);
|
||||
resolve(history);
|
||||
});
|
||||
})
|
||||
.catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPageContributorsState {
|
||||
contributors: PageContributor[];
|
||||
loading: boolean;
|
||||
error: string;
|
||||
}
|
||||
|
||||
function Loading(props){
|
||||
if (!props.show){
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ margin: '0 auto' }}><Spinner label={strings.Loading} /></div>
|
||||
);
|
||||
}
|
||||
|
||||
function ErrorMessage(props){
|
||||
if (!props.message){
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MessageBar messageBarType={MessageBarType.error}>{props.message}</MessageBar>
|
||||
);
|
||||
}
|
||||
|
||||
export default class PageContributors extends React.Component<IPageContributorsProps, IPageContributorsState> {
|
||||
|
||||
constructor(props, state) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
contributors: [] as PageContributor[],
|
||||
loading: true,
|
||||
error: null
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this._loadUsers();
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<null> {
|
||||
|
||||
let facepileProps: IFacepileProps = {
|
||||
personaSize: this.props.personaSize,
|
||||
maxDisplayablePersonas: this.props.numberOfFaces,
|
||||
overflowButtonType: OverflowButtonType.descriptive,
|
||||
overflowButtonProps: {
|
||||
},
|
||||
personas: this.state.contributors.map((contributor) => {
|
||||
return { personaName: contributor.displayName, imageUrl: contributor.imageUrl };
|
||||
})
|
||||
};
|
||||
const contributors: JSX.Element = this.state.contributors.length ? <Facepile {...facepileProps} /> : <div />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Loading show={this.state.loading}/>
|
||||
<ErrorMessage message={this.state.error}/>
|
||||
{contributors}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IPageContributorsProps, prevState: IPageContributorsState, prevContext: any): void {
|
||||
if (this.props.pageUrl !== prevProps.pageUrl) {
|
||||
this._loadUsers();
|
||||
}
|
||||
}
|
||||
|
||||
private _loadUsers(): void {
|
||||
if (Environment.type === EnvironmentType.Local) {
|
||||
PageContributorsMockData.get().then((response) => {
|
||||
this._setContributors(response);
|
||||
});
|
||||
}
|
||||
else if (Environment.type == EnvironmentType.SharePoint ||
|
||||
Environment.type == EnvironmentType.ClassicSharePoint) {
|
||||
PageContributorsService.getPageContributors(this.props.pageUrl || location.pathname).then(
|
||||
(response) => {
|
||||
this._setContributors(response);
|
||||
},
|
||||
error => this._showError(error)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _setContributors(contributors: PageContributor[]) {
|
||||
this.setState((prevState: IPageContributorsState, currentProps: IPageContributorsProps): IPageContributorsState => {
|
||||
prevState.loading = false;
|
||||
prevState.error = null;
|
||||
prevState.contributors = contributors;
|
||||
return prevState;
|
||||
});
|
||||
}
|
||||
private _showError(error: any) {
|
||||
this.setState((prevState: IPageContributorsState, currentProps: IPageContributorsProps): IPageContributorsState => {
|
||||
prevState.loading = false;
|
||||
prevState.error = `${error.status} ${error.message} : ${error.stack}`;
|
||||
prevState.contributors = [];
|
||||
return prevState;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Displays page contributors in reverse chronological order",
|
||||
"PropertyPaneNbPersonasText": "Maximum number of persons to display",
|
||||
"PropertyPaneBasicGroupName": "General",
|
||||
"PropertyPanePersonaSizeText": "Icons size",
|
||||
"PropertyPaneIconsSizeTiny": "tiny",
|
||||
"PropertyPaneIconsSizeEES": "extraExtraSmall",
|
||||
"PropertyPaneIconsSizeES": "extraSmall",
|
||||
"PropertyPaneIconsSizeS": "small",
|
||||
"PropertyPaneIconsSizeR": "regular",
|
||||
"PropertyPaneIconsSizeL": "large",
|
||||
"PropertyPaneIconsSizeEL": "extraLarge",
|
||||
"PropertyPanePageUrlText": "Page server relative URL (leave empty for current page)",
|
||||
"Loading": "Loading..."
|
||||
}
|
||||
});
|
20
samples/react-pagecontributors/src/webparts/pageContributors/loc/mystrings.d.ts
vendored
Normal file
20
samples/react-pagecontributors/src/webparts/pageContributors/loc/mystrings.d.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
declare interface IPageContributorsStrings {
|
||||
PropertyPaneDescription: string;
|
||||
PropertyPaneNbPersonasText: string;
|
||||
PropertyPaneBasicGroupName: string;
|
||||
PropertyPanePersonaSizeText: string;
|
||||
PropertyPaneIconsSizeTiny: string;
|
||||
PropertyPaneIconsSizeEES: string;
|
||||
PropertyPaneIconsSizeES: string;
|
||||
PropertyPaneIconsSizeS: string;
|
||||
PropertyPaneIconsSizeR: string;
|
||||
PropertyPaneIconsSizeL: string;
|
||||
PropertyPaneIconsSizeEL: string;
|
||||
PropertyPanePageUrlText: string;
|
||||
Loading: string;
|
||||
}
|
||||
|
||||
declare module 'pageContributorsStrings' {
|
||||
const strings: IPageContributorsStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"es6-collections",
|
||||
"webpack-env"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Type definitions for Microsoft ODSP projects
|
||||
// Project: ODSP
|
||||
|
||||
/* Global definition for UNIT_TEST builds
|
||||
Code that is wrapped inside an if(UNIT_TEST) {...}
|
||||
block will not be included in the final bundle when the
|
||||
--ship flag is specified */
|
||||
declare const UNIT_TEST: boolean;
|
||||
|
||||
/* Global defintion for SPO builds */
|
||||
declare const DATACENTER: boolean;
|
|
@ -0,0 +1 @@
|
|||
/// <reference path="@ms/odsp.d.ts" />
|
|
@ -66,6 +66,7 @@ react-script-editor | Mikael Svenson ([@mikaelsvenson](http://www.twitter.com/mi
|
|||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|March 10th, 2017|Initial release
|
||||
1.0.1|August 8th, 2017|Updated SPFx version and CSS loading
|
||||
|
||||
## 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.**
|
||||
|
@ -73,12 +74,23 @@ Version|Date|Comments
|
|||
---
|
||||
|
||||
## Minimal Path to Awesome
|
||||
### Local testing
|
||||
|
||||
- Clone this repository
|
||||
- In the command line run:
|
||||
- `npm install`
|
||||
- `gulp serve`
|
||||
|
||||
### Deploy
|
||||
* Set CDN path in config\write-manifest.json to where you want to host the web part
|
||||
* E.g.: https://<tenant>.sharepoint.com/sites/CDN/SiteAssets/SPFx/<partname>
|
||||
* gulp --ship
|
||||
* gulp package-solution --ship
|
||||
* Copy contents of temp\deploy to the CDN folder
|
||||
* Upload .sppkg file from sharepoint\solution to your tenant App Catalog
|
||||
* E.g.: https://<tenant>.sharepoint.com/sites/AppCatalog/AppCatalog
|
||||
* Add the web part to a site collection, and test it on a page
|
||||
|
||||
## Features
|
||||
This web part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
|
|
|
@ -6,5 +6,7 @@
|
|||
"outputPath": "./dist/script-editor.bundle.js"
|
||||
}
|
||||
],
|
||||
"externals": {}
|
||||
}
|
||||
"externals": {
|
||||
"office-ui-fabric-react": "https://publiccdn.sharepointonline.com/techmikael.sharepoint.com/11510075fe4212d19d3e6d07c91981263dd697bf111cb1e5f0efb15de0ec08b382cde399/2.34.2/office-ui-fabric-react.bundle.min.js"
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"solution": {
|
||||
"name": "Modern Script Editor web part by Puzzlepart",
|
||||
"id": "1425175f-3ed8-44d2-8fc4-dd1497191294",
|
||||
"version": "1.0.0.0"
|
||||
"version": "1.0.0.1"
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/pzl-script-editor.sppkg"
|
||||
|
|
|
@ -7,21 +7,22 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-client-base": "~1.0.0",
|
||||
"@microsoft/sp-core-library": "~1.0.0",
|
||||
"@microsoft/sp-webpart-base": "~1.0.0",
|
||||
"@microsoft/sp-core-library": "~1.1.0",
|
||||
"@microsoft/sp-webpart-base": "~1.1.0",
|
||||
"@types/react": "0.14.46",
|
||||
"@types/react-addons-shallow-compare": "0.14.17",
|
||||
"@types/react-addons-test-utils": "0.14.15",
|
||||
"@types/react-addons-update": "0.14.14",
|
||||
"@types/react-dom": "0.14.18",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"office-ui-fabric-react": "2.34.2",
|
||||
"react": "15.4.2",
|
||||
"react-dom": "15.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.0.0",
|
||||
"@microsoft/sp-module-interfaces": "~1.0.0",
|
||||
"@microsoft/sp-webpart-workbench": "~1.0.0",
|
||||
"@microsoft/sp-build-web": "~1.1.0",
|
||||
"@microsoft/sp-module-interfaces": "~1.1.0",
|
||||
"@microsoft/sp-webpart-workbench": "~1.1.0",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0"
|
||||
|
@ -31,4 +32,4 @@
|
|||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||
|
||||
"id": "3a328f0a-99c4-4b28-95ab-fe0847f657a3",
|
||||
"alias": "ScriptEditorWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "0.0.1",
|
||||
"version": "*", // The "*" signifies that the version should be taken from the package.json
|
||||
"manifestVersion": 2,
|
||||
|
||||
/**
|
||||
* This property should only be set to true if it is certain that the webpart does not
|
||||
* allow arbitrary scripts to be called
|
||||
*/
|
||||
"safeWithCustomScriptDisabled": false,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "3a328f0a-99c4-4b28-95ab-fe0847f657a3",
|
||||
"group": { "default": "Puzzlepart" },
|
||||
|
|
|
@ -12,14 +12,12 @@ import { IScriptEditorProps } from './components/IScriptEditorProps';
|
|||
import { IScriptEditorWebPartProps } from './IScriptEditorWebPartProps';
|
||||
|
||||
export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEditorWebPartProps> {
|
||||
|
||||
public save: (script: string) => void = (script: string) => {
|
||||
this.properties.script = script;
|
||||
this.render();
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
const element: React.ReactElement<IScriptEditorProps> = React.createElement(
|
||||
ScriptEditor,
|
||||
{
|
||||
|
@ -41,7 +39,11 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
|
|||
}
|
||||
|
||||
protected renderLogo(domElement: HTMLElement) {
|
||||
domElement.innerHTML = '<div style="margin-top: 30px"><img src="//www.puzzlepart.com/wp-content/uploads/2017/02/Puzzlepart-Logo-Digital-webheader200.png" onerror="this.style.display = \'none\'";" style="width:50%; float:right">';
|
||||
domElement.innerHTML = `
|
||||
<div style="margin-top: 30px">
|
||||
<div style="float:right">Author: <a href="mailto:mikael.svenson@puzzlepart.com" tabindex="-1">Mikael Svenson</a></div>
|
||||
<div style="float:right"><img src="//www.puzzlepart.com/wp-content/uploads/2017/08/Pzl-LogoType-200.png" onerror="this.style.display = \'none\'";"></div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url('overrides.css');
|
||||
//@import url(https://publiccdn.sharepointonline.com/techmikael.sharepoint.com/11510075fe4212d19d3e6d07c91981263dd697bf111cb1e5f0efb15de0ec08b382cde399/5.0.1/office-ui-fabric.min.css);
|
||||
|
||||
.scriptEditor {
|
||||
.container {
|
||||
|
|
|
@ -1,16 +1,35 @@
|
|||
import * as React from 'react';
|
||||
import styles from './ScriptEditor.module.scss';
|
||||
import { IScriptEditorProps } from './IScriptEditorProps';
|
||||
import { Dialog, DialogType, DialogFooter, Button, ButtonType, TextField } from 'office-ui-fabric-react';
|
||||
import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react';
|
||||
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react';
|
||||
import { TextField } from 'office-ui-fabric-react';
|
||||
import { loadStyles } from '@microsoft/load-themed-styles';
|
||||
require('./overrides.css');
|
||||
|
||||
export default class ScriptEditor extends React.Component<IScriptEditorProps, any> {
|
||||
constructor() {
|
||||
super();
|
||||
this.loadCss();
|
||||
this.state = {
|
||||
showDialog: false
|
||||
};
|
||||
}
|
||||
|
||||
public async loadCss() {
|
||||
if (window["UIFabricLoaded"]) {
|
||||
return;
|
||||
}
|
||||
const response = await fetch("https://publiccdn.sharepointonline.com/techmikael.sharepoint.com/11510075fe4212d19d3e6d07c91981263dd697bf111cb1e5f0efb15de0ec08b382cde399/5.0.1/office-ui-fabric.min.css");
|
||||
if (response.ok) {
|
||||
response.text().then((data: any) => {
|
||||
loadStyles(data);
|
||||
window["UIFabricLoaded"] = true;
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.setState({ script: this.props.script, loaded: this.props.script });
|
||||
}
|
||||
|
@ -33,17 +52,20 @@ export default class ScriptEditor extends React.Component<IScriptEditorProps, an
|
|||
}
|
||||
|
||||
public render(): React.ReactElement<IScriptEditorProps> {
|
||||
if (!window["UIFabricLoaded"]) {
|
||||
return <span />;
|
||||
}
|
||||
const viewMode = <span dangerouslySetInnerHTML={{ __html: this.state.script }}></span>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div >
|
||||
<div className={styles.scriptEditor}>
|
||||
<div className={styles.container}>
|
||||
<div className={`ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
|
||||
<div className="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
|
||||
<span className="ms-font-xl ms-fontColor-white">The Modern Script Editor web part!</span>
|
||||
<p className="ms-font-l ms-fontColor-white"></p>
|
||||
<Button description='Opens the Sample Dialog' onClick={this._showDialog.bind(this)}>Edit snippet</Button>
|
||||
<div className={`pzl-Grid-row pzl-bgColor-themeDark pzl-fontColor-white ${styles.row}`}>
|
||||
<div className="pzl-Grid-col pzl-u-lg10 pzl-u-xl8 pzl-u-xlPush2 pzl-u-lgPush1">
|
||||
<span className="pzl-font-xl pzl-fontColor-white">The Modern Script Editor web part!</span>
|
||||
<p className="pzl-font-l pzl-fontColor-white"></p>
|
||||
<DefaultButton description='Opens the Sample Dialog' onClick={this._showDialog.bind(this)}>Edit snippet</DefaultButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,11 +81,11 @@ export default class ScriptEditor extends React.Component<IScriptEditorProps, an
|
|||
>
|
||||
<TextField multiline rows={15} onChanged={this._onScriptEditorTextChanged.bind(this)} value={this.state.script} />
|
||||
<DialogFooter>
|
||||
<Button buttonType={ButtonType.primary} onClick={this._closeDialog.bind(this)}>Save</Button>
|
||||
<Button onClick={this._cancelDialog.bind(this)}>Cancel</Button>
|
||||
<PrimaryButton onClick={this._closeDialog.bind(this)}>Save</PrimaryButton>
|
||||
<DefaultButton onClick={this._cancelDialog.bind(this)}>Cancel</DefaultButton>
|
||||
</DialogFooter>
|
||||
{viewMode}
|
||||
</Dialog>
|
||||
</div>);
|
||||
</div >);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
// The number of spaces a tab is equal to.
|
||||
"editor.tabSize": 2,
|
||||
|
||||
// When enabled, will trim trailing whitespace when you save a file.
|
||||
"files.trimTrailingWhitespace": true,
|
||||
|
||||
// Controls if the editor should automatically close brackets after opening them
|
||||
"editor.autoClosingBrackets": false,
|
||||
|
||||
// Configure glob patterns for excluding files and folders.
|
||||
"search.exclude": {
|
||||
"**/bower_components": true,
|
||||
"**/node_modules": true,
|
||||
"coverage": true,
|
||||
"dist": true,
|
||||
"lib-amd": true,
|
||||
"lib": true,
|
||||
"temp": true
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "0.1.0",
|
||||
"command": "gulp",
|
||||
"isShellCommand": true,
|
||||
"showOutput": "always",
|
||||
"args": [
|
||||
"--no-color"
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "bundle",
|
||||
"isBuildCommand": true,
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"isTestCommand": true,
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "serve",
|
||||
"isWatching": true,
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
## todo-webpart-sample
|
||||
|
||||
This is where you include your web part docs.
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-drop2-red.svg)
|
||||
|
||||
## Building the code
|
||||
|
||||
```bash
|
||||
git clone the repo
|
||||
npm i
|
||||
npm i -g gulp
|
||||
gulp
|
||||
```
|
||||
|
||||
This package produces the following:
|
||||
|
||||
* lib/* commonjs components - this allows this package to be reused from other packages.
|
||||
* dist/* - a single bundle containing the components used for uploading to a cdn pointing a registered Sharepoint webpart library to.
|
||||
* example/* a test page that hosts all components in this package.
|
||||
|
||||
## Build options
|
||||
|
||||
gulp nuke - TODO
|
||||
gulp test - TODO
|
||||
gulp watch - TODO
|
||||
gulp build - TODO
|
||||
gulp deploy - TODO
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"entries": [
|
||||
{
|
||||
"entry": "./lib/webparts/todo-step-1/TodoWebPart.js",
|
||||
"manifest": "./src/webparts/todo-step-1/TodoWebPart.manifest.json",
|
||||
"outputPath": "./dist/todo-step-1.bundle.js"
|
||||
},
|
||||
{
|
||||
"entry": "./lib/webparts/todo-step-2/TodoWebPart.js",
|
||||
"manifest": "./src/webparts/todo-step-2/TodoWebPart.manifest.json",
|
||||
"outputPath": "./dist/todo-step-2.bundle.js"
|
||||
},
|
||||
{
|
||||
"entry": "./lib/webparts/todo-step-3/TodoWebPart.js",
|
||||
"manifest": "./src/webparts/todo-step-3/TodoWebPart.manifest.json",
|
||||
"outputPath": "./dist/todo-step-3.bundle.js"
|
||||
},
|
||||
{
|
||||
"entry": "./lib/webparts/todo-step-4/TodoWebPart.js",
|
||||
"manifest": "./src/webparts/todo-step-4/TodoWebPart.manifest.json",
|
||||
"outputPath": "./dist/todo-step-4.bundle.js"
|
||||
}
|
||||
],
|
||||
"externals": {
|
||||
"@microsoft/sp-client-base": "node_modules/@microsoft/sp-client-base/dist/sp-client-base.js",
|
||||
"@microsoft/sp-client-preview": "node_modules/@microsoft/sp-client-preview/dist/sp-client-preview.js",
|
||||
"@microsoft/sp-lodash-subset": "node_modules/@microsoft/sp-lodash-subset/dist/sp-lodash-subset.js",
|
||||
"office-ui-fabric-react": "node_modules/office-ui-fabric-react/dist/office-ui-fabric-react.js",
|
||||
"react": "node_modules/react/dist/react.min.js",
|
||||
"react-dom": "node_modules/react-dom/dist/react-dom.min.js",
|
||||
"react-dom/server": "node_modules/react-dom/dist/react-dom-server.min.js"
|
||||
},
|
||||
"localizedResources": {
|
||||
"todoStep1Strings": "webparts/todo-step-1/loc/{locale}.js",
|
||||
"todoStep2Strings": "webparts/todo-step-2/loc/{locale}.js",
|
||||
"todoStep3Strings": "webparts/todo-step-3/loc/{locale}.js",
|
||||
"todoStep4Strings": "webparts/todo-step-4/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"solution": {
|
||||
"name": "todo-webpart-sample-client-side-solution",
|
||||
"id": "99a1fe26-363c-4980-b7c7-f14322a071ed",
|
||||
"version": "1.0.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "todo-webpart-sample.spapp"
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"name": "todo-webpart-sample",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-lodash-subset": "~0.2.0",
|
||||
"@microsoft/sp-client-base": "~0.2.0",
|
||||
"@microsoft/sp-client-preview": "~0.2.0",
|
||||
"office-ui-fabric": "2.6.1",
|
||||
"office-ui-fabric-react": "0.46.1",
|
||||
"react": "0.14.8",
|
||||
"react-addons-update": "0.14.8",
|
||||
"react-dom": "0.14.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~0.5.0",
|
||||
"@microsoft/sp-module-interfaces": "~0.2.0",
|
||||
"@microsoft/sp-webpart-workbench": "~0.2.0",
|
||||
"gulp": "~3.9.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp nuke",
|
||||
"test": "gulp test"
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
|
||||
<ListInstance
|
||||
Title="DefaultTodoList"
|
||||
OnQuickLaunch="TRUE"
|
||||
TemplateType="171"
|
||||
FeatureId="F9CE21F8-F437-4f7e-8BC6-946378C850F0"
|
||||
Url="Lists/DefaultTodoList"
|
||||
Description="Default list for the Todo sample webpart"
|
||||
>
|
||||
</ListInstance>
|
||||
</Elements>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Feature
|
||||
xmlns="http://schemas.microsoft.com/sharepoint/"
|
||||
Title="Todo web part"
|
||||
Id="771d8fd4-46ce-421d-a61c-79c55e1fba19"
|
||||
Scope="Web"
|
||||
Description="Provision default tasks list (DefaultTodoList) for todo web part."
|
||||
Hidden="FALSE"
|
||||
>
|
||||
</Feature>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AppPartConfig
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://schemas.microsoft.com/sharepoint/2012/app/partconfiguration"
|
||||
>
|
||||
<Id>771d8fd4-46ce-421d-a61c-79c55e1fba19</Id>
|
||||
</AppPartConfig>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship
|
||||
Type="http://schemas.microsoft.com/sharepoint/2012/app/relationships/partconfiguration"
|
||||
Target="/TodoWebPartFeature.xml.config.xml"
|
||||
Id="r1"
|
||||
/>
|
||||
<Relationship
|
||||
Type="http://schemas.microsoft.com/sharepoint/2012/app/relationships/feature-elementmanifest"
|
||||
Target="/List/Elements.xml"
|
||||
Id="r2"
|
||||
/>
|
||||
</Relationships>
|
|
@ -1,5 +0,0 @@
|
|||
var context = require.context('.', true, /.+\.test\.js?$/);
|
||||
|
||||
context.keys().forEach(context);
|
||||
|
||||
module.exports = context;
|
|
@ -1,3 +0,0 @@
|
|||
export interface ITodoWebPartProps {
|
||||
description: string;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
## Todo sample web part step 1
|
||||
|
||||
In this step, we create an empty React web part using Yeoman SharePoint Generator.
|
|
@ -1,21 +0,0 @@
|
|||
.todo {
|
||||
.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 {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.listItem {
|
||||
max-width: 715px;
|
||||
margin: 5px auto 5px auto;
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.button {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||
|
||||
"id": "e31b9536-2df9-4d43-9ab2-1fdaaff05154",
|
||||
"componentType": "WebPart",
|
||||
"version": "0.0.1",
|
||||
"manifestVersion": 2,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "e31b9536-2df9-4d43-9ab2-1fdaaff05154",
|
||||
"group": { "default": "Under Development" },
|
||||
"title": { "default": "Todo step 1" },
|
||||
"description": { "default": "Todo sample webpart step 1" },
|
||||
"officeFabricIconFontName": "BulletedList",
|
||||
"properties": {
|
||||
"description": "Todo"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneSettings,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-client-preview';
|
||||
|
||||
import * as strings from 'todoStep1Strings';
|
||||
import Todo, { ITodoProps } from './components/Todo';
|
||||
import { ITodoWebPartProps } from './ITodoWebPartProps';
|
||||
|
||||
/**
|
||||
* This is the todo sample web part built using the SharePoint Framework.
|
||||
*
|
||||
* Find out more docs and tutorials at:
|
||||
* https://github.com/SharePoint/sp-dev-docs/wiki
|
||||
*/
|
||||
export default class TodoWebPart extends BaseClientSideWebPart<ITodoWebPartProps> {
|
||||
/**
|
||||
* Override the base render() implementation to render the todo sample web part.
|
||||
*/
|
||||
public render(): void {
|
||||
const element: React.ReactElement<ITodoProps> = React.createElement(Todo, {
|
||||
description: this.properties.description
|
||||
});
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* The PropertyPane settings for properties to be configured in PropertyPane.
|
||||
*/
|
||||
protected get propertyPaneSettings(): IPropertyPaneSettings {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('description', {
|
||||
label: strings.DescriptionFieldLabel
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import { css } from 'office-ui-fabric-react';
|
||||
|
||||
import styles from '../Todo.module.scss';
|
||||
import { ITodoWebPartProps } from '../ITodoWebPartProps';
|
||||
|
||||
export interface ITodoProps extends ITodoWebPartProps {
|
||||
}
|
||||
|
||||
export default class Todo extends React.Component<ITodoProps, {}> {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className={styles.todo}>
|
||||
<div className={styles.container}>
|
||||
<div className={css('ms-Grid-row ms-bgColor-themeDark ms-fontColor-white', styles.row)}>
|
||||
<div className='ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1'>
|
||||
<span className='ms-font-xl ms-fontColor-white'>
|
||||
Welcome to SharePoint!
|
||||
</span>
|
||||
<p className='ms-font-l ms-fontColor-white'>
|
||||
Customize SharePoint experiences using Web Parts.
|
||||
</p>
|
||||
<p className='ms-font-l ms-fontColor-white'>
|
||||
{this.props.description}
|
||||
</p>
|
||||
<a
|
||||
className={css('ms-Button', styles.button)}
|
||||
href='https://github.com/SharePoint/sp-dev-docs/wiki'
|
||||
>
|
||||
<span className='ms-Button-label'>Learn more</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
declare interface ITodoStep1Strings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'todoStep1Strings' {
|
||||
const strings: ITodoStep1Strings;
|
||||
export = strings;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue