Merge branch 'dev'

This commit is contained in:
VesaJuvonen 2019-03-10 18:34:41 +02:00
commit 5cdcd80e02
240 changed files with 101196 additions and 39098 deletions

3
package-lock.json generated
View File

@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

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

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,10 @@
{
"@microsoft/generator-sharepoint": {
"version": "1.6.0",
"libraryName": "spfx-photos-sol-react",
"libraryId": "a4282f62-8f32-4d1f-bf80-d25bc778c069",
"environment": "spo",
"packageManager": "npm",
"isCreatingSolution": true
}
}

View File

@ -0,0 +1,62 @@
# Image Slider from Photo Gallery using Taxonomy Filter
## Summary
This webpart display the image in slider based on the filter of Taxonomy from Property panel. Images are stored in PhotoGallery and tagged with Taxonomy. This web part showcase 3 important implementation.
- How to add the Terms in the propertypage and pass the values to react component
- How to filter the list based on Taxonomy and extract the Image URL
- Implementation of Slick Slider
<img src=https://github.com/sudhir007rawat/sp-dev-fx-webparts/blob/sample-Contribution/samples/react-ImageSlider-List-TaxonomyFilter/assets/ImageSlider.gif />
## 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)
> Update accordingly as needed.
## Prerequisites
> PhotoGalley list names "Photos" and Managed Metadata field attached to Site collection Terms
> Upload few photos in the "Photos" library and tag it.
## Solution
Solution|Author(s)
--------|---------
react-ImageSlider-List-TaxonomyFilter | Sudhir Rawat
## Version history
Version|Date|Comments
-------|----|--------
1.0|March 1, 2019 |Initial release
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
---
## Minimal Path to Awesome
- Clone this repository
- in the command line run:
- `npm install`
- `gulp serve`
> Include any additional steps as needed.
## Features
This web part show the images carousel which is picking from the list based on terms filter.
This Web Part illustrates the following concepts on top of the SharePoint Framework:
- How to add the Terms in the propertypage and pass the values to react component
- How to filter the list based on Taxonomy and extract the Image URL
- Implementation of Slick Slider
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/readme-template" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

View File

@ -0,0 +1,21 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"photo-gallery-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/photoGallery/PhotoGalleryWebPart.js",
"manifest": "./src/webparts/photoGallery/PhotoGalleryWebPart.manifest.json"
}
]
}
},
"externals": {
"jquery": "https://code.jquery.com/jquery-3.1.0.min.js"
},
"localizedResources": {
"PhotoGalleryWebPartStrings": "lib/webparts/photoGallery/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
}
}

View File

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

View File

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

View File

@ -0,0 +1,12 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-photos-sol-react-client-side-solution",
"id": "a4282f62-8f32-4d1f-bf80-d25bc778c069",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/spfx-photos-sol-react.sppkg"
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,38 @@
{
"name": "spfx-photos-sol-react",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/sp-core-library": "1.6.0",
"@microsoft/sp-lodash-subset": "1.6.0",
"@microsoft/sp-office-ui-fabric-core": "1.6.0",
"@microsoft/sp-webpart-base": "1.6.0",
"@pnp/spfx-property-controls": "1.14.1",
"@types/es6-promise": "0.0.33",
"@types/react": "15.6.6",
"@types/react-dom": "15.5.6",
"@types/react-slick": "^0.23.3",
"@types/webpack-env": "1.13.1",
"react": "15.6.2",
"react-dom": "15.6.2",
"react-slick": "^0.23.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.6.0",
"@microsoft/sp-module-interfaces": "1.6.0",
"@microsoft/sp-webpart-workbench": "1.6.0",
"tslint-microsoft-contrib": "~5.0.0",
"gulp": "~3.9.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"ajv": "~5.2.2"
}
}

View File

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

View File

@ -0,0 +1,26 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "940d8dc5-0ce9-4725-9197-3a5edbdea27f",
"alias": "PhotoGalleryWebPart",
"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": "PhotoGallery" },
"description": { "default": "PhotoGallery description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "PhotoGallery"
}
}]
}

View File

@ -0,0 +1,85 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { PropertyFieldTermPicker } from '@pnp/spfx-property-controls/lib/PropertyFieldTermPicker';
import { IPickerTerms } from '@pnp/spfx-property-controls/lib/PropertyFieldTermPicker';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import * as strings from 'PhotoGalleryWebPartStrings';
import PhotoGallery from './components/PhotoGallery';
import { IPhotoGalleryProps } from './components/IPhotoGalleryProps';
export interface IPhotoGalleryWebPartProps {
description: string;
terms : IPickerTerms;
}
export default class PhotoGalleryWebPart extends BaseClientSideWebPart<IPhotoGalleryWebPartProps> {
protected get disableReactivePropertyChanges(): boolean {
return true;
}
public render(): void {
const element: React.ReactElement<IPhotoGalleryProps > = React.createElement(
PhotoGallery,
{
description: this.properties.description,
tagkeywords : this.properties.terms,
siteurl:this.context.pageContext.web.absoluteUrl,
spHttpClient:this.context.spHttpClient
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyFieldTermPicker('terms', {
label: 'Select Keywords',
panelTitle: 'Select Keywords',
initialValues: this.properties.terms,
allowMultipleSelections: true,
excludeSystemGroup: false,
onPropertyChange: this.onPropertyPaneFieldChanged,
properties: this.properties,
context: this.context,
onGetErrorMessage: null,
deferredValidationTime: 0,
limitByGroupNameOrID: 'Site Collection - sudhirrawatdev.sharepoint.com-sites-TeamTestSite',
limitByTermsetNameOrID: 'Keyword',
key: 'termSetsPickerFieldId'
})
]
}
]
}
]
};
}
}

View File

@ -0,0 +1,10 @@
import { IPickerTerms } from '@pnp/spfx-property-controls/lib/PropertyFieldTermPicker';
import { SPHttpClient } from '@microsoft/sp-http';
import {IPhotoGallery} from '../model/IPhotoGallery'
export interface IPhotoGalleryProps {
description: string;
tagkeywords: IPickerTerms;
siteurl:string;
spHttpClient:SPHttpClient;
}

View File

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

View File

@ -0,0 +1,142 @@
import * as React from 'react';
import styles from './PhotoGallery.module.scss';
import { IPhotoGalleryProps } from './IPhotoGalleryProps';
import { escape } from '@microsoft/sp-lodash-subset';
import {SPHttpClient,SPHttpClientResponse} from '@microsoft/sp-http';
import Slider from 'react-slick';
import {IPhotoGallery} from '../model/IPhotoGallery';
import 'slick-carousel/slick/slick-theme.css';
import 'slick-carousel/slick/slick.css';
export default class PhotoGallery extends React.Component<IPhotoGalleryProps,any> {
constructor (props) {
super(props);
this.state = {
currentboxvalue:String,
photoGallery: [ {
photoURL:"",
photoID:""
}
],
};
this.getPhotos=this.getPhotos.bind(this);
this.loadPhotos=this.loadPhotos.bind(this);
this.getPhotosURL=this.getPhotosURL.bind(this);
}
componentDidUpdate(prevProps) {
if (prevProps.tagkeywords === this.props.tagkeywords)
{
// this.loadPhotos()
}
else
{
this.loadPhotos();
}
}
componentDidMount(){
this.loadPhotos();
}
getPhotos(termSet) {
this.props.spHttpClient.get(this.props.siteurl + `/_api/web/lists/GetByTitle('Photos')/Items?$filter=TaxCatchAll/IdForTerm eq '` + termSet +`'`,
SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
if (response.ok) {
response.json().then((responseJSON) => {
if (responseJSON!=null && responseJSON.value!=null){
for (var i=0; i < responseJSON.value.length; i++) {
this.getPhotosURL(responseJSON.value[i].ID)
//so on
}
}
});
}
});
}
loadPhotos()
{
if (this.props.tagkeywords != undefined)
{
if (this.props.tagkeywords.length >=1)
{
this.state.photoGallery.length=0;
this.props.tagkeywords.map((tg) => this.getPhotos(tg.key));
}
}
//this.getPhotosURL(2);
//this.getPhotosURL(3);
}
getPhotosURL(itemid) {
this.props.spHttpClient.get(this.props.siteurl + `/_api/web/lists/GetByTitle('Photos')/Items(`+itemid+`)?$select=FileRef/FileRef`,
SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
if (response.ok) {
response.json().then((responseJSON) => {
if (responseJSON!=null){
let items:any[] = responseJSON;
this.setState(prevState => ({
photoGallery: [...prevState.photoGallery, { "photoURL" : items["FileRef"], "photoID" : itemid }]
}))
}
});
}
});
}
public render(): React.ReactElement<IPhotoGalleryProps> {
debugger;
const settings = {
dots: true,
infinite: true,
slidesToShow: 1,
slidesToScroll: 1,
autoplay: true,
speed: 3000,
autoplaySpeed: 3000,
cssEase: "linear"
};
return (
<div>
{ this.state.photoGallery != undefined &&
<Slider {...settings}>
{
this.state.photoGallery.map((pg)=> <this.PhotoComponent imgurl={pg.photoURL} />)
}
</Slider>
}
{ this.state.photoGallery.length == 1 && this.state.photoGallery[0].photoID == "" && <h1>Please configure the web part</h1>
}
</div>
);
}
PhotoComponent=props =>
(
<div>
<img src={props.imgurl} />
</div>
);
}

View File

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

View File

@ -0,0 +1,5 @@
export interface IPhotoGallery
{
photoURL:string;
photoID:number;
}

View File

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

View File

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

View File

@ -1,8 +1,12 @@
{
"@microsoft/generator-sharepoint": {
"version": "1.1.1",
"version": "1.7.1",
"libraryName": "react-app-settings",
"libraryId": "9573efb7-06d1-4134-aa8d-f6b4803d6096",
"environment": "spo"
"environment": "spo",
"isDomainIsolated": false,
"isCreatingSolution": false,
"packageManager": "npm",
"componentType": "webpart"
}
}

View File

@ -2,25 +2,17 @@
## 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.
This sample shows how AppSettings.ts 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 continuous integration (CI/CD) automation. The AppSettings.ts is transpiled/compiled with your SPFx solution which differs from the way the web.config. With .Net web.config file we would be able to update independently without the need of compiling DLLs. If that behavior is required, you can store your app settings in a SharePoint list and change them from there. However, that will have performance degradation over if the setting was part of the SPFx code where the logic can get a setting value in milliseconds.
![SPFx React app settings webpart](./assets/spfx-appSettings-json.PNG)
![SPFx React app settings webpart](./assets/app-settings-class.PNG)
### Easy to replace values in appSettings.json if DEV, QA, PROD environments.
### Replace values in AppSettings.ts if DEV, QA, PROD environments with Azure DevOps pipeline.
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.
Azure DevOps pipelines configurations are included to demonstrate how the AppSettings.ts values can be changed per different environments. Please refer to the `devops/configurations` folder to see how this can be setup for your pipeline.
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/drop-1.4.1-green.svg)
![drop](https://img.shields.io/badge/drop-1.7.1-green.svg)
## Applies to
@ -44,6 +36,7 @@ Version|Date|Comments
-------|----|--------
0.0.1|August 03, 2017 | Initial commit
0.0.2|March 08, 2018 | Update to SPFx 1.4.1
0.0.3|March 03, 2019 | Update to SPFx 1.7.1
## 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.**

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,18 +1,27 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"react-app-settings-bundle": {
"ice-cream-shop-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/reactAppSettings/ReactAppSettingsWebPart.js",
"manifest": "./src/webparts/reactAppSettings/ReactAppSettingsWebPart.manifest.json"
"entrypoint": "./lib/webparts/iceCreamShop/IceCreamShopWebPart.js",
"manifest": "./src/webparts/iceCreamShop/IceCreamShopWebPart.manifest.json"
}
]
},
"ice-cream-lorry-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/iceCreamLorry/IceCreamLorryWebPart.js",
"manifest": "./src/webparts/iceCreamLorry/IceCreamLorryWebPart.manifest.json"
}
]
}
},
"localizedResources": {
"reactAppSettingsStrings": "lib/webparts/reactAppSettings/loc/{locale}.js"
"IceCreamShopWebPartStrings": "lib/webparts/iceCreamShop/loc/{locale}.js",
"IceCreamLorryWebPartStrings": "lib/webparts/iceCreamLorry/loc/{locale}.js"
},
"externals": {}
}

View File

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

View File

@ -1,4 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "react-app-settings",

View File

@ -1,9 +1,11 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "react-app-settings-client-side-solution",
"id": "9573efb7-06d1-4134-aa8d-f6b4803d6096",
"version": "1.0.0.0"
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/react-app-settings.sppkg"

View File

@ -1,4 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"initialPage": "https://localhost:5432/workbench",
"https": true,

View File

@ -1,45 +0,0 @@
{
"$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

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

View File

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"ice-cream-shop-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/iceCreamShop/IceCreamShopWebPart.js",
"manifest": "./src/webparts/iceCreamShop/IceCreamShopWebPart.manifest.json"
}
]
}
},
"localizedResources": {
"IceCreamShopWebPartStrings": "lib/webparts/iceCreamShop/loc/{locale}.js",
"IceCreamLorryWebPartStrings": "lib/webparts/iceCreamLorry/loc/{locale}.js"
},
"externals": {}
}

View File

@ -0,0 +1,5 @@
export class AppSettings {
public static readonly tenantUrl: string = "https://contoso-prod.sharepoint.com/";
public static readonly assetsUrl: string = "https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/9.6.1/css/fabric.min.css";
}

View File

@ -0,0 +1,20 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "4e6bdbca-212c-40b2-8de8-7d877b6c6db9",
"alias": "IceCreamShopWebPart",
"componentType": "WebPart",
"version": "*",
"manifestVersion": 2,
"requiresCustomScript": false,
"supportsFullBleed": true,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": { "default": "Other" },
"title": { "default": "IceCreamShop" },
"description": { "default": "IceCreamShop description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "IceCreamShop"
}
}]
}

View File

@ -0,0 +1,67 @@
# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
trigger:
- master
jobs:
- job: DEV
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- script: |
npm i
gulp bundle --ship
gulp package-solution --ship
displayName: 'Build DEV package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/sharepoint/solution/react-app-settings.sppkg'
artifactName: 'DEV-sppkg'
displayName: 'Publish DEV env SPFx artifacts'
- job: PROD
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- task: CopyFiles@2
inputs:
sourceFolder: '$(Build.SourcesDirectory)/devops/configurations/PROD'
contents: '**/*'
targetFolder: '$(Build.SourcesDirectory)'
overWrite: true
- script: |
npm i
gulp bundle --ship
gulp package-solution --ship
displayName: 'Build PROD package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/sharepoint/solution/react-app-settings.sppkg'
artifactName: 'PROD-sppkg'
displayName: 'Publish PROD env SPFx artifacts'
- job: Release_Scripts
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/devops/release/'
artifactName: 'Release-scripts'
displayName: 'Publish release scripts'

View File

@ -0,0 +1,72 @@
# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
trigger:
- master
jobs:
- job: DEV
pool:
vmImage: 'windows-2019'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- script: |
npm i
displayName: 'Npm install'
- script: |
gulp bundle --ship && gulp package-solution --ship
displayName: 'Build DEV package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)\sharepoint\solution\react-app-settings.sppkg'
artifactName: 'DEV-sppkg'
displayName: 'Publish DEV env SPFx artifacts'
- job: PROD
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- task: CopyFiles@2
inputs:
sourceFolder: '$(Build.SourcesDirectory)/devops/configurations/PROD'
contents: '**/*'
targetFolder: '$(Build.SourcesDirectory)'
overWrite: true
- script: |
npm i
displayName: 'Npm install'
- script: |
gulp bundle --ship
gulp package-solution --ship
displayName: 'Build PROD package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/sharepoint/solution/react-app-settings.sppkg'
artifactName: 'PROD-sppkg'
displayName: 'Publish PROD env SPFx artifacts'
- job: Release_Scripts
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/devops/release/'
artifactName: 'Release-scripts'
displayName: 'Publish release scripts'

View File

@ -0,0 +1,71 @@
# Node.js
# Build a general Node.js project with npm.
# Add steps that analyze code, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
trigger:
- master
pool:
vmImage: 'Ubuntu-16.04'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- task: CopyFiles@2
inputs:
sourceFolder: '$(Build.SourcesDirectory)'
contents: '**/*'
targetFolder: '$(Build.ArtifactStagingDirectory)/dev'
displayName: 'CopyFiles to folder staging/dev'
- script: |
cd '$(Build.ArtifactStagingDirectory)/dev'
npm i
gulp bundle --ship
gulp package-solution --ship
displayName: 'Build DEV package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)/dev/sharepoint/solution/react-app-settings.sppkg'
artifactName: 'DEV-sppkg'
displayName: 'Publish DEV env SPFx artifacts'
- task: CopyFiles@2
inputs:
sourceFolder: '$(Build.SourcesDirectory)'
contents: '**/*'
targetFolder: '$(Build.ArtifactStagingDirectory)/prod'
displayName: 'CopyFiles to folder staging/prod'
- task: CopyFiles@2
inputs:
sourceFolder: '$(Build.SourcesDirectory)/devops/configurations/PROD'
contents: '**/*'
targetFolder: '$(Build.ArtifactStagingDirectory)/prod'
overWrite: true
displayName: 'Apply PROD configuration (overrite dev env files)'
- script: |
cd '$(Build.ArtifactStagingDirectory)/prod'
rm package-lock.json
npm i
gulp bundle --ship
gulp package-solution --ship
displayName: 'Build PROD package'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)/prod/sharepoint/solution/react-app-settings.sppkg'
artifactName: 'PROD-sppkg'
displayName: 'Publish PROD env SPFx artifacts'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/devops/release/'
artifactName: 'Release-scripts'
displayName: 'Publish release scripts'

View File

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"ice-cream-shop-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/iceCreamShop/IceCreamShopWebPart.js",
"manifest": "./src/webparts/iceCreamShop/IceCreamShopWebPart.manifest.json"
}
]
}
},
"localizedResources": {
"IceCreamShopWebPartStrings": "lib/webparts/iceCreamShop/loc/{locale}.js",
"IceCreamLorryWebPartStrings": "lib/webparts/iceCreamLorry/loc/{locale}.js"
},
"externals": {}
}

View File

@ -0,0 +1,5 @@
export class AppSettings {
public static readonly tenantUrl: string = "https://contoso-prod.sharepoint.com/1";
public static readonly assetsUrl: string = "https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/9.6.1/css/fabric.min.css";
}

View File

@ -0,0 +1,20 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "4e6bdbca-212c-40b2-8de8-7d877b6c6db9",
"alias": "IceCreamShopWebPart",
"componentType": "WebPart",
"version": "*",
"manifestVersion": 2,
"requiresCustomScript": false,
"supportsFullBleed": true,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": { "default": "Other" },
"title": { "default": "IceCreamShop" },
"description": { "default": "IceCreamShop description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "IceCreamShop"
}
}]
}

View File

@ -0,0 +1,25 @@
#!/bin/bash
SITE=$1
EMAIL=$2
PASS=$3
SCOPE=$4
ISDEV=$5
npm i -g @pnp/office365-cli
o365 version
# You have to run "o365 spo login https://contoso.sharepoint.com"
# to agree with the consent first time
sppkg_path="PROD-sppkg"
if [ ${ISDEV,,} = "true" ]
then
sppkg_path="DEV-sppkg"
fi
o365 spo login $SITE --authType password --userName $EMAIL --password $PASS
o365 spo app add --filePath "./_SPFx build/$sppkg_path/react-app-settings.sppkg" --appCatalogUrl $SITE --scope $SCOPE --overwrite
o365 spo app deploy --name react-app-settings.sppkg --appCatalogUrl $SITE --scope $SCOPE --skipFeatureDeployment

View File

@ -0,0 +1,19 @@
param(
$site,
$accessToken,
[ValidateSet("Site", "Tenant")]
$scope,
[switch]$isDev
)
# Install pnp powershell module on your release agent/vm
$sppkgPath = "PROD-sppkg"
if ($isDev.ToString) {
$sppkgPath = "DEV-sppkg"
}
Connect-PnPOnline $site -AccessToken $accessToken
Add-PnPApp -Path "./_SPFx build/$sppkgPath/react-app-settings.sppkg" -Scope $scope -Publish

View File

@ -3,10 +3,5 @@
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.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
build.initialize(gulp);

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,31 @@
{
"name": "react-app-settings",
"version": "0.0.2",
"version": "0.0.3",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"dependencies": {
"@microsoft/sp-core-library": "~1.4.1",
"@microsoft/sp-webpart-base": "~1.4.1",
"@types/webpack-env": ">=1.12.1 <1.14.0",
"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.7.1",
"@microsoft/sp-webpart-base": "1.7.1",
"@microsoft/sp-lodash-subset": "1.7.1",
"@microsoft/sp-office-ui-fabric-core": "1.7.1",
"@types/es6-promise": "0.0.33",
"@types/react": "16.4.2",
"@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-addons-test-utils": "0.14.15"
"@types/react-dom": "16.0.5",
"@types/webpack-env": "1.13.1",
"react": "16.3.2",
"react-dom": "16.3.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "~1.4.1",
"@microsoft/sp-module-interfaces": "~1.4.1",
"@microsoft/sp-webpart-workbench": "~1.4.1",
"@microsoft/sp-build-web": "1.7.1",
"@microsoft/sp-module-interfaces": "1.7.1",
"@microsoft/sp-webpart-workbench": "1.7.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"
},
"scripts": {
"build": "gulp bundle",

View File

@ -0,0 +1,5 @@
export class AppSettings {
public static readonly tenantUrl: string = "https://contoso-dev.sharepoint.com/";
public static readonly assetsUrl: string = "https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/4.1.0/css/fabric.min.css";
}

View File

@ -1,10 +0,0 @@
declare interface IAppSettings {
tenantUrl: string;
assetsUrl: string;
webSearchUrl: string;
}
declare module 'appSettings' {
const appSettings: IAppSettings;
export = appSettings;
}

View File

@ -1,5 +0,0 @@
{
"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"
}

View File

@ -1,98 +0,0 @@
'use strict';
var fs = require('fs'),
build = require('@microsoft/sp-build-web');
/**
* Verifies if the appSettings.json and appSettings.d.ts 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;

View File

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

View File

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "6a8e85b0-fb77-4206-aced-cdfc53a9b6c1",
"alias": "IceCreamLorryWebPart",
"componentType": "WebPart",
"version": "*",
"manifestVersion": 2,
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": { "default": "Other" },
"title": { "default": "IceCreamLorry" },
"description": { "default": "IceCreamLorry description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "IceCreamLorry"
}
}]
}

View File

@ -0,0 +1,60 @@
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 'IceCreamLorryWebPartStrings';
import IceCreamLorry from './components/IceCreamLorry';
import { IIceCreamLorryProps } from './components/IIceCreamLorryProps';
export interface IIceCreamLorryWebPartProps {
description: string;
}
export default class IceCreamLorryWebPart extends BaseClientSideWebPart<IIceCreamLorryWebPartProps> {
public render(): void {
const element: React.ReactElement<IIceCreamLorryProps > = React.createElement(
IceCreamLorry,
{
description: this.properties.description
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}

View File

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

View File

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

View File

@ -0,0 +1,32 @@
import * as React from 'react';
import styles from './IceCreamLorry.module.scss';
import { IIceCreamLorryProps } from './IIceCreamLorryProps';
/**
* Import the AppSettings and use them to call apis.
*/
import { AppSettings } from '../../../AppSettings';
export default class IceCreamLorry extends React.Component<IIceCreamLorryProps, {}> {
public render(): React.ReactElement<IIceCreamLorryProps> {
return (
<div className={ styles.iceCreamLorry }>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
<span className={ styles.title }>Welcome to the PnP ice cream lorry!</span>
<code>
<pre>
appSettings.tenantUrl: {AppSettings.tenantUrl}
</pre>
<pre>
appSettings.assetsUrl: {AppSettings.assetsUrl}
</pre>
</code>
</div>
</div>
</div>
</div>
);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

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

View File

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "4e6bdbca-212c-40b2-8de8-7d877b6c6db9",
"alias": "IceCreamShopWebPart",
"componentType": "WebPart",
"version": "*",
"manifestVersion": 2,
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": { "default": "Other" },
"title": { "default": "IceCreamShop" },
"description": { "default": "IceCreamShop description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "IceCreamShop"
}
}]
}

View File

@ -7,16 +7,19 @@ import {
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';
import * as strings from 'IceCreamShopWebPartStrings';
import IceCreamShop from './components/IceCreamShop';
import { IIceCreamShopProps } from './components/IIceCreamShopProps';
export default class ReactAppSettingsWebPart extends BaseClientSideWebPart<IReactAppSettingsWebPartProps> {
export interface IIceCreamShopWebPartProps {
description: string;
}
export default class IceCreamShopWebPart extends BaseClientSideWebPart<IIceCreamShopWebPartProps> {
public render(): void {
const element: React.ReactElement<IReactAppSettingsProps> = React.createElement(
ReactAppSettings,
const element: React.ReactElement<IIceCreamShopProps > = React.createElement(
IceCreamShop,
{
description: this.properties.description
}
@ -25,6 +28,10 @@ export default class ReactAppSettingsWebPart extends BaseClientSideWebPart<IReac
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}

View File

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

View File

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

View File

@ -0,0 +1,32 @@
import * as React from 'react';
import styles from './IceCreamShop.module.scss';
import { IIceCreamShopProps } from './IIceCreamShopProps';
/**
* Import the AppSettings and use them to call apis.
*/
import { AppSettings } from '../../../AppSettings';
export default class IceCreamShop extends React.Component<IIceCreamShopProps, {}> {
public render(): React.ReactElement<IIceCreamShopProps> {
return (
<div className={ styles.iceCreamShop }>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
<span className={ styles.title }>Welcome to PnP ice cream shop!</span>
<code>
<pre>
appSettings.tenantUrl: {AppSettings.tenantUrl}
</pre>
<pre>
appSettings.assetsUrl: {AppSettings.assetsUrl}
</pre>
</code>
</div>
</div>
</div>
</div>
);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

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

View File

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

View File

@ -1,26 +0,0 @@
{
"$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"
}
}]
}

View File

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

View File

@ -1,52 +0,0 @@
.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;
}
}
}

View File

@ -1,38 +0,0 @@
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, {}> {
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>
);
}
}

View File

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

View File

@ -1,9 +0,0 @@
/// <reference types="mocha" />
import { assert } from 'chai';
describe('ReactAppSettingsWebPart', () => {
it('should do something', () => {
assert.ok(true);
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,48 @@
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.2/MicrosoftTeams.schema.json",
"manifestVersion": "1.2",
"packageName": "IceCreamShop",
"id": "4e6bdbca-212c-40b2-8de8-7d877b6c6db9",
"version": "0.1",
"developer": {
"name": "SPFx + Teams Dev",
"websiteUrl": "https://products.office.com/en-us/sharepoint/collaboration",
"privacyUrl": "https://privacy.microsoft.com/en-us/privacystatement",
"termsOfUseUrl": "https://www.microsoft.com/en-us/servicesagreement"
},
"name": {
"short": "IceCreamShop"
},
"description": {
"short": "Shows how settings can be stored in appSettings.json file so they can easly be maintained for different envoirements like QEV, QA, STAGE, PROD",
"full": "Shows how settings can be stored in appSettings.json file so they can easly be maintained for different envoirements like QEV, QA, STAGE, PROD"
},
"icons": {
"outline": "tab20x20.png",
"color": "tab96x96.png"
},
"accentColor": "#004578",
"configurableTabs": [
{
"configurationUrl": "https://{teamSiteDomain}{teamSitePath}/_layouts/15/TeamsLogon.aspx?SPFX=true&dest={teamSitePath}/_layouts/15/teamshostedapp.aspx%3FopenPropertyPane=true%26teams%26componentId=4e6bdbca-212c-40b2-8de8-7d877b6c6db9",
"canUpdateConfiguration": true,
"scopes": [
"team"
]
}
],
"validDomains": [
"*.login.microsoftonline.com",
"*.sharepoint.com",
"*.sharepoint-df.com",
"spoppe-a.akamaihd.net",
"spoprod-a.akamaihd.net",
"resourceseng.blob.core.windows.net",
"msft.spoppe.com"
],
"webApplicationInfo": {
"resource": "https://{teamSiteDomain}",
"id": "00000003-0000-0ff1-ce00-000000000000"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -2,12 +2,14 @@
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
@ -21,5 +23,12 @@
"dom",
"es2015.collection"
]
}
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"lib"
]
}

View File

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

View File

@ -1,11 +0,0 @@
// 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;

View File

@ -1 +0,0 @@
/// <reference path="@ms/odsp.d.ts" />

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-image-gallery/.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,11 @@
{
"@microsoft/generator-sharepoint": {
"isCreatingSolution": true,
"environment": "spo",
"version": "1.6.0",
"libraryName": "image-gallery",
"libraryId": "876cbbe8-6974-4676-9da3-5c190ac8164f",
"packageManager": "npm",
"componentType": "webpart"
}
}

View File

@ -0,0 +1,62 @@
# Filterable Image Gallery Web Part
## Summary
This sample describe a SPFX application which implement an image gallery with taxonomy base filtering and typed search. This application also implement pagination.
![Filterable Image Gallery web part built on the SharePoint Framework using React](./assets/image-gallery.gif)
## 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)
> Update accordingly as needed.
## Prerequisites
> Any special pre-requisites?
## Solution
Solution|Author(s)
--------|---------
react-image-gallery | Ejaz Hussain
## Version history
Version|Date|Comments
-------|----|--------
1.0|March 01, 2019|Initial release
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
---
## Minimal Path to Awesome
- Clone this repository
- in the command line run:
- `npm install`
- `gulp serve`
> Include any additional steps as needed.
- Create a Department Term set with associated child terms, for example, HR, Information Services, Sales, Marketing
- Create an Image Library and add some sample images
- Tag each image with Department Metadata Column
- Also fill in Title field for each image, this is require for typed search functionality
## Features
Here are main features for this application
- Taxonomy based filtering
- Typed Search
- Right side popup panel
- Server side pagination using REST API
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/readme-template" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -0,0 +1,19 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"image-gallery-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/imageGallery/ImageGalleryWebPart.js",
"manifest": "./src/webparts/imageGallery/ImageGalleryWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"ImageGalleryWebPartStrings": "lib/webparts/imageGallery/loc/{locale}.js",
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
}
}

View File

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

View File

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

View File

@ -0,0 +1,13 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "image-gallery-client-side-solution",
"id": "876cbbe8-6974-4676-9da3-5c190ac8164f",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/image-gallery.sppkg"
}
}

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More