Update SPFx
This commit is contained in:
parent
39ea25afc2
commit
c2a2ec7ffd
|
@ -9,6 +9,7 @@ node_modules
|
|||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
release
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
!dist
|
||||
config
|
||||
|
||||
gulpfile.js
|
||||
|
||||
release
|
||||
src
|
||||
temp
|
||||
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
|
||||
*.log
|
||||
|
||||
.yo-rc.json
|
||||
.vscode
|
|
@ -1,11 +1,16 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"plusBeta": false,
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.6.0",
|
||||
"version": "1.14.0",
|
||||
"libraryName": "image-gallery",
|
||||
"libraryId": "876cbbe8-6974-4676-9da3-5c190ac8164f",
|
||||
"libraryId": "e55194cd-8581-401c-b4fc-06169480813f",
|
||||
"environment": "spo",
|
||||
"packageManager": "npm",
|
||||
"solutionName": "image-gallery",
|
||||
"solutionShortDescription": "image-gallery description",
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,37 @@
|
|||
# Filterable Image Gallery
|
||||
|
||||
## Summary
|
||||
|
||||
This sample describes an SPFx application which implements an image gallery with taxonomy base filtering and typed search. This application also implements 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-1.6.0-green.svg)
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.14](https://img.shields.io/badge/SPFx-1.14-green.svg)
|
||||
![Node.js v14 | v12](https://img.shields.io/badge/Node.js-v14%20%7C%20v12-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||
* [Microsoft 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-image-gallery | Ejaz Hussain
|
||||
react-image-gallery | [Ejaz Hussain](https://github.com/ejazhussain) ([@EjazHussain_](https://twitter.com/EjazHussain_))
|
||||
react-image-gallery | [Ari Gunawan](https://github.com/AriGunawan) ([@arigunawan3023](https://twitter.com/arigunawan3023))
|
||||
|
||||
## 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.**
|
||||
|
||||
---
|
||||
1.1|May 23, 2022|Update SPFx version, update README, and fix minor issues
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
|
@ -39,12 +41,13 @@ Version|Date|Comments
|
|||
- `gulp serve`
|
||||
|
||||
|
||||
- Create a Department Term set with associated child terms, for example, HR, Information Services, Sales, Marketing
|
||||
- Create a Departments 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 the main features for this application
|
||||
|
||||
- Taxonomy-based filtering
|
||||
|
@ -52,4 +55,30 @@ Here are the main features for this application
|
|||
- Right-side popup panel
|
||||
- Server-side pagination using REST API
|
||||
|
||||
## Help
|
||||
|
||||
We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
If you're having issues building the solution, please run [spfx doctor](https://pnp.github.io/cli-microsoft365/cmd/spfx/spfx-doctor/) from within the solution folder to diagnose incompatibility issues with your environment.
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3A%22sample%3A%20react-image-gallery%22) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=react-image-gallery) and see what the community is saying.
|
||||
|
||||
If you encounter any issues using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected%2Csample%3A%20react-image-gallery&template=bug-report.yml&sample=react-image-gallery&authors=@arigunawan%20@ejazhussain&title=react-image-gallery%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aquestion%2Csample%3A%20react-image-gallery&template=question.yml&sample=react-image-gallery&authors=@arigunawan%20@ejazhussain&title=react-image-gallery%20-%20).
|
||||
|
||||
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aenhancement%2Csample%3A%20react-image-gallery&template=suggestion.yml&sample=react-image-gallery&authors=@arigunawan%20@ejazhussain&title=react-image-gallery%20-%20).
|
||||
|
||||
## 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.**
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-image-gallery" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"workingDir": "./release/assets/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "image-gallery",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
|
|
|
@ -3,9 +3,36 @@
|
|||
"solution": {
|
||||
"name": "image-gallery-client-side-solution",
|
||||
"id": "876cbbe8-6974-4676-9da3-5c190ac8164f",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.1.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"websiteUrl": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"mpnId": "Undefined-1.14.0"
|
||||
},
|
||||
"metadata": {
|
||||
"shortDescription": {
|
||||
"default": "image-gallery description"
|
||||
},
|
||||
"longDescription": {
|
||||
"default": "image-gallery description"
|
||||
},
|
||||
"screenshotPaths": [],
|
||||
"videoUrl": "",
|
||||
"categories": []
|
||||
},
|
||||
"features": [
|
||||
{
|
||||
"title": "image-gallery Feature",
|
||||
"description": "The feature that activates elements of the image-gallery solution.",
|
||||
"id": "afeca86e-a632-48ce-a9eb-b5a4a3e94d85",
|
||||
"version": "1.0.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/image-gallery.sppkg"
|
||||
|
|
|
@ -2,9 +2,5 @@
|
|||
"$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/"
|
||||
}
|
||||
"initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
'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);
|
||||
var getTasks = build.rig.getTasks;
|
||||
build.rig.getTasks = function () {
|
||||
var result = getTasks.call(build.rig);
|
||||
|
||||
result.set('serve', result.get('serve-deprecated'));
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
build.initialize(require('gulp'));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -2,41 +2,33 @@
|
|||
"name": "react-image-gallery",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"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/common": "^1.2.7",
|
||||
"@pnp/graph": "^1.2.7",
|
||||
"@pnp/logging": "^1.2.7",
|
||||
"@pnp/odata": "^1.2.7",
|
||||
"@pnp/sp": "^1.2.7",
|
||||
"@pnp/spfx-controls-react": "1.11.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "15.6.6",
|
||||
"@types/react-dom": "15.5.6",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"react": "15.6.2",
|
||||
"react-dom": "15.6.2",
|
||||
"react-js-pagination": "^3.0.2"
|
||||
"@microsoft/sp-core-library": "1.14.0",
|
||||
"@microsoft/sp-lodash-subset": "1.14.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.14.0",
|
||||
"@microsoft/sp-property-pane": "1.14.0",
|
||||
"@microsoft/sp-webpart-base": "1.14.0",
|
||||
"@pnp/spfx-controls-react": "^3.7.2",
|
||||
"office-ui-fabric-react": "7.174.1",
|
||||
"react": "16.13.1",
|
||||
"react-dom": "16.13.1",
|
||||
"react-js-pagination": "^3.0.3"
|
||||
},
|
||||
"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"
|
||||
"@types/react": "16.9.51",
|
||||
"@types/react-dom": "16.9.8",
|
||||
"@microsoft/sp-build-web": "1.14.0",
|
||||
"@microsoft/sp-tslint-rules": "1.14.0",
|
||||
"@microsoft/sp-module-interfaces": "1.14.0",
|
||||
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
|
||||
"gulp": "~4.0.2",
|
||||
"ajv": "~5.2.2",
|
||||
"@types/webpack-env": "1.13.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,147 +1,94 @@
|
|||
import { SPHttpClient, SPHttpClientResponse, ISPHttpClientOptions } from '@microsoft/sp-http';
|
||||
import { reject } from 'lodash';
|
||||
import { IListService, IImage } from '../Interfaces';
|
||||
import { sp, spODataEntityArray, Item } from "@pnp/sp";
|
||||
import Constants from '../Common/constants';
|
||||
import { stringIsNullOrEmpty } from '@pnp/common';
|
||||
|
||||
import { SPHttpClient } from "@microsoft/sp-http";
|
||||
import { IListService } from "../Interfaces";
|
||||
|
||||
export class ListService implements IListService {
|
||||
private spHttpClient: SPHttpClient;
|
||||
|
||||
private spHttpClient: SPHttpClient;
|
||||
constructor(spHttpClient?: SPHttpClient) {
|
||||
this.spHttpClient = spHttpClient;
|
||||
}
|
||||
|
||||
constructor(spHttpClient?: SPHttpClient) {
|
||||
this.spHttpClient = spHttpClient;
|
||||
public async readItems(url: string): Promise<any> {
|
||||
try {
|
||||
const response = await this.spHttpClient.get(
|
||||
url,
|
||||
SPHttpClient.configurations.v1,
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/json;odata=nometadata",
|
||||
"odata-version": "",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const items: any = await response.json();
|
||||
let result = {};
|
||||
if (items.value.length) {
|
||||
result = {
|
||||
items: items.value,
|
||||
nextLink: items["odata.nextLink"],
|
||||
};
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
public async readItems(url: string): Promise<any> {
|
||||
try {
|
||||
// return new Promise<any>(async (resolve) => {
|
||||
|
||||
const response = await this.spHttpClient.get(url, SPHttpClient.configurations.v1,
|
||||
{
|
||||
headers: {
|
||||
'Accept': 'application/json;odata=nometadata',
|
||||
'odata-version': ''
|
||||
}
|
||||
});
|
||||
// this.spHttpClient.get(url, SPHttpClient.configurations.v1,
|
||||
// {
|
||||
// headers: {
|
||||
// 'Accept': 'application/json;odata=nometadata',
|
||||
// 'odata-version': ''
|
||||
// }
|
||||
// }).then((response: SPHttpClientResponse): Promise<{ value: number }> => {
|
||||
// return response.json();
|
||||
// }).then((response: { value: number }): void => {
|
||||
|
||||
const items: any = await response.json();
|
||||
let result = {};
|
||||
if (items.value.length) {
|
||||
// resolve(response.value);
|
||||
// });
|
||||
|
||||
result = {
|
||||
items: items.value,
|
||||
nextLink: items["odata.nextLink"]
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
// });
|
||||
}
|
||||
|
||||
public async getListItemsCount(url: string): Promise<any> {
|
||||
try {
|
||||
const response = await this.spHttpClient.get(
|
||||
url,
|
||||
SPHttpClient.configurations.v1,
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/json;odata=nometadata",
|
||||
"odata-version": "",
|
||||
},
|
||||
}
|
||||
catch (error) {
|
||||
return error;
|
||||
}
|
||||
);
|
||||
|
||||
const result: any = await response.json();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// return new Promise<any>(async (resolve) => {
|
||||
|
||||
// this.spHttpClient.get(url, SPHttpClient.configurations.v1,
|
||||
// {
|
||||
// headers: {
|
||||
// 'Accept': 'application/json;odata=nometadata',
|
||||
// 'odata-version': ''
|
||||
// }
|
||||
// }).then((response: SPHttpClientResponse): Promise<{ value: number }> => {
|
||||
// return response.json();
|
||||
// }).then((response: { value: number }): void => {
|
||||
|
||||
// resolve(response.value);
|
||||
// });
|
||||
|
||||
// });
|
||||
|
||||
return result.value;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
public async getListItemsCount(url: string): Promise<any> {
|
||||
try {
|
||||
|
||||
const response = await this.spHttpClient.get(url, SPHttpClient.configurations.v1,
|
||||
{
|
||||
headers: {
|
||||
'Accept': 'application/json;odata=nometadata',
|
||||
'odata-version': ''
|
||||
}
|
||||
});
|
||||
|
||||
const result: any = await response.json();
|
||||
|
||||
return result.value;
|
||||
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// return new Promise<any>(async (resolve) => {
|
||||
|
||||
// this.spHttpClient.get(url, SPHttpClient.configurations.v1,
|
||||
// {
|
||||
// headers: {
|
||||
// 'Accept': 'application/json;odata=nometadata',
|
||||
// 'odata-version': ''
|
||||
// }
|
||||
// }).then((response: SPHttpClientResponse): Promise<{ value: number }> => {
|
||||
// return response.json();
|
||||
// }).then((response: { value: number }): void => {
|
||||
|
||||
// resolve(response.value);
|
||||
// });
|
||||
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// return new Promise<any>(async (resolve) => {
|
||||
|
||||
// this.spHttpClient.get(url, SPHttpClient.configurations.v1,
|
||||
// {
|
||||
// headers: {
|
||||
// 'Accept': 'application/json;odata=nometadata',
|
||||
// 'odata-version': ''
|
||||
// }
|
||||
// }).then((response: SPHttpClientResponse): Promise<{ value: number }> => {
|
||||
// return response.json();
|
||||
// }).then((response: { value: number }): void => {
|
||||
|
||||
// resolve(response.value);
|
||||
// });
|
||||
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -12,15 +12,18 @@
|
|||
// 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,
|
||||
"supportedHosts": ["SharePointWebPart", "TeamsPersonalApp", "TeamsTab", "SharePointFullPage"],
|
||||
"supportsThemeVariants": true,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": { "default": "Other" },
|
||||
"title": { "default": "imageGallery" },
|
||||
"description": { "default": "imageGallery description" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"title": { "default": "React Image Gallery" },
|
||||
"description": { "default": "React component that shows image gallery from a list" },
|
||||
"officeFabricIconFontName": "PhotoCollection",
|
||||
"properties": {
|
||||
"description": "imageGallery"
|
||||
"description": "imageGallery",
|
||||
"pageSize": 5
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -2,17 +2,16 @@ import * as React from 'react';
|
|||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneSlider
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
|
||||
import * as strings from 'ImageGalleryWebPartStrings';
|
||||
import ImageGallery from './components/ImageGallery';
|
||||
import { IImageGalleryProps } from './components/IImageGalleryProps';
|
||||
import ConfigureWebPart from './components/ConfigureWebPart/ConfigureWebPart';
|
||||
import { sp } from '@pnp/sp';
|
||||
import { ListService } from '../../Services/ListService';
|
||||
|
||||
export interface IImageGalleryWebPartProps {
|
||||
|
@ -22,17 +21,12 @@ export interface IImageGalleryWebPartProps {
|
|||
}
|
||||
|
||||
export default class ImageGalleryWebPart extends BaseClientSideWebPart<IImageGalleryWebPartProps> {
|
||||
private listService: ListService
|
||||
|
||||
private listService: ListService;
|
||||
|
||||
protected async onInit(): Promise<void> {
|
||||
const _ = await super.onInit();
|
||||
|
||||
this.listService = new ListService(this.context.spHttpClient);
|
||||
|
||||
sp.setup({
|
||||
spfxContext: this.context
|
||||
});
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
@ -43,17 +37,15 @@ export default class ImageGalleryWebPart extends BaseClientSideWebPart<IImageGal
|
|||
// }
|
||||
// );
|
||||
|
||||
|
||||
let element: any;
|
||||
|
||||
if (this.properties.imageLibrary && this.properties.pageSize) {
|
||||
|
||||
element = React.createElement<IImageGalleryProps>(
|
||||
ImageGallery,
|
||||
{
|
||||
listName: this.properties.imageLibrary,
|
||||
context: this.context,
|
||||
siteUrl: this.context.pageContext.site.absoluteUrl,
|
||||
siteUrl: this.context.pageContext.web.absoluteUrl,
|
||||
pageSize: this.properties.pageSize
|
||||
|
||||
}
|
||||
|
@ -72,7 +64,6 @@ export default class ImageGalleryWebPart extends BaseClientSideWebPart<IImageGal
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
|
@ -83,6 +74,7 @@ export default class ImageGalleryWebPart extends BaseClientSideWebPart<IImageGal
|
|||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected get disableReactivePropertyChanges(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
@ -91,7 +83,6 @@ export default class ImageGalleryWebPart extends BaseClientSideWebPart<IImageGal
|
|||
return {
|
||||
pages: [
|
||||
{
|
||||
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -1,21 +1,17 @@
|
|||
import * as React from 'react';
|
||||
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
|
||||
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import styles from './ConfigureWebPart.module.scss';
|
||||
|
||||
|
||||
|
||||
export interface IConfigureWebPartProps {
|
||||
webPartContext: IWebPartContext;
|
||||
webPartContext: WebPartContext;
|
||||
title: string;
|
||||
description?: string;
|
||||
buttonText?: string;
|
||||
}
|
||||
|
||||
|
||||
const ConfigureWebPart: React.SFC<IConfigureWebPartProps> = (props) => {
|
||||
|
||||
const ConfigureWebPart: React.FunctionComponent<IConfigureWebPartProps> = (props) => {
|
||||
const {
|
||||
webPartContext,
|
||||
title,
|
||||
|
|
|
@ -4,10 +4,10 @@ export interface IImageGalleryState {
|
|||
showPanel: boolean;
|
||||
selectedImage?: IImage;
|
||||
showLoader: boolean;
|
||||
itemsNotFoundMessage?: string,
|
||||
sQuery?: string,
|
||||
dQuery?: string
|
||||
itemsNotFound?: boolean,
|
||||
itemsNotFoundMessage?: string;
|
||||
sQuery?: string;
|
||||
dQuery?: string;
|
||||
itemsNotFound?: boolean;
|
||||
itemCount?: number;
|
||||
pageSize?: number;
|
||||
currentPage?: number;
|
||||
|
|
|
@ -179,4 +179,9 @@
|
|||
background-color: #fff;
|
||||
border: 1px solid rgba(0, 0, 0, .125);
|
||||
}
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
|
@ -1,26 +1,19 @@
|
|||
import * as React from 'react';
|
||||
import styles from './ImageGallery.module.scss';
|
||||
import { IImageGalleryProps } from './IImageGalleryProps';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import { css, classNamesFunction, IStyleFunction } from '@uifabric/utilities/lib';
|
||||
import { css } from '@uifabric/utilities/lib';
|
||||
import { TaxonomyPicker, IPickerTerms } from "@pnp/spfx-controls-react/lib/TaxonomyPicker";
|
||||
import { TextField } from 'office-ui-fabric-react/lib/TextField';
|
||||
import { IListService, IImage } from '../../../Interfaces';
|
||||
import { ListService } from '../../../Services/ListService';
|
||||
import { Panel, PanelType } from 'office-ui-fabric-react/lib/Panel';
|
||||
import { objectDefinedNotNull, stringIsNullOrEmpty } from '@pnp/common';
|
||||
import { Label } from 'office-ui-fabric-react/lib/Label';
|
||||
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
|
||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
|
||||
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
|
||||
import { Button } from 'office-ui-fabric-react/lib/Button';
|
||||
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import { IImageGalleryState } from './IImageGalleryState';
|
||||
|
||||
|
||||
|
||||
export default class ImageGallery extends React.Component<IImageGalleryProps, IImageGalleryState> {
|
||||
|
||||
private _spService: IListService;
|
||||
private selectQuery: string[] = [];
|
||||
private expandQuery: string[] = [];
|
||||
|
@ -41,10 +34,7 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
pageSize: this.props.pageSize,
|
||||
currentPage: 1,
|
||||
nextLink: "",
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
this._onTaxPickerChange = this._onTaxPickerChange.bind(this);
|
||||
this._onClickNext = this._onClickNext.bind(this);
|
||||
|
@ -52,17 +42,12 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
this._onImageClick = this._onImageClick.bind(this);
|
||||
this._onSearchChange = this._onSearchChange.bind(this);
|
||||
|
||||
|
||||
|
||||
this._spService = new ListService(this.props.context.spHttpClient);
|
||||
}
|
||||
|
||||
|
||||
public async componentDidMount() {
|
||||
//Get Images from the library
|
||||
|
||||
|
||||
|
||||
let value = await this._spService.getListItemsCount(`${this.props.siteUrl}/_api/web/lists/GetByTitle('${this.props.listName}')/ItemCount`);
|
||||
this.setState({
|
||||
itemCount: value
|
||||
|
@ -83,17 +68,16 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
});
|
||||
let response = await this._spService.readItems(url);
|
||||
|
||||
if (objectDefinedNotNull(response)) {
|
||||
|
||||
if (objectDefinedNotNull(response.nextLink)) {
|
||||
if (response) {
|
||||
if (response.nextLink) {
|
||||
this.urlCollection.push(response.nextLink);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
showLoader: false,
|
||||
items: response.items,
|
||||
status: `Showing items ${(this.state.currentPage - 1) * this.props.pageSize + 1} - ${((this.state.currentPage - 1) * this.props.pageSize) + response.items.length} of ${this.state.itemCount}`
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
this.setState({
|
||||
|
@ -102,12 +86,10 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
status: "",
|
||||
itemsNotFound: true
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async _onClickNext() {
|
||||
|
||||
this.setState({
|
||||
currentPage: this.state.currentPage + 1,
|
||||
showLoader: true
|
||||
|
@ -115,12 +97,13 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
let url = this.urlCollection[this.urlCollection.length - 1];
|
||||
this._readItems(url);
|
||||
}
|
||||
|
||||
private async _onClickPrevious() {
|
||||
let url = "";
|
||||
if (this.urlCollection.length > 1) {
|
||||
this.setState({
|
||||
currentPage: this.state.currentPage - 1
|
||||
})
|
||||
});
|
||||
|
||||
this.urlCollection.pop();
|
||||
url = this.urlCollection[this.urlCollection.length - 1];
|
||||
|
@ -143,8 +126,6 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private buildQueryParams(taxQuery?: string, searchQuery?: string): string {
|
||||
this.selectQuery = [];
|
||||
this.expandQuery = [];
|
||||
|
@ -179,33 +160,30 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
return queryParam + selectColumns + filterColumns;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private buildFilterQuery(taxQuery: string, searchQuery: string) {
|
||||
let result: string = "";
|
||||
|
||||
if (!stringIsNullOrEmpty(taxQuery) && stringIsNullOrEmpty(searchQuery)) {
|
||||
if (!taxQuery && searchQuery) {
|
||||
result = `TaxCatchAll/Term eq '${taxQuery}'`;
|
||||
}
|
||||
|
||||
if (stringIsNullOrEmpty(taxQuery) && !stringIsNullOrEmpty(searchQuery)) {
|
||||
if (taxQuery && !searchQuery) {
|
||||
result = `startswith(Title,'${searchQuery}')`;
|
||||
}
|
||||
|
||||
if (!stringIsNullOrEmpty(taxQuery) && !stringIsNullOrEmpty(searchQuery)) {
|
||||
if (!taxQuery && !searchQuery) {
|
||||
result = `(TaxCatchAll/Term eq '${taxQuery}') and (startswith(Title,'${searchQuery}'))`;
|
||||
}
|
||||
if (stringIsNullOrEmpty(taxQuery) && stringIsNullOrEmpty(searchQuery)) {
|
||||
|
||||
if (taxQuery && searchQuery) {
|
||||
result = "";
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
private async _onTaxPickerChange(terms: IPickerTerms) {
|
||||
|
||||
private async _onTaxPickerChange(terms: IPickerTerms) {
|
||||
this.urlCollection = [];
|
||||
let query = "";
|
||||
|
||||
|
@ -225,9 +203,9 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
let url = `${this.props.siteUrl}/_api/web/lists/GetByTitle('${this.props.listName}')/items/${queryParam}`;
|
||||
this.urlCollection.push(url);
|
||||
this._readItems(url);
|
||||
|
||||
}
|
||||
private async _onSearchChange(query: any) {
|
||||
|
||||
private async _onSearchChange(event: any, query: any) {
|
||||
this.urlCollection = [];
|
||||
this.setState({
|
||||
sQuery: query
|
||||
|
@ -235,12 +213,10 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
|
||||
let queryParam = this.buildQueryParamsTotalFilteredItems(this.state.dQuery, query);
|
||||
let response = await this._spService.readItems(`${this.props.siteUrl}/_api/web/lists/GetByTitle('${this.props.listName}')/items/${queryParam}`);
|
||||
if (objectDefinedNotNull(response)) {
|
||||
|
||||
if (response) {
|
||||
this.setState({
|
||||
itemCount: response.items.length
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
this.setState({
|
||||
|
@ -248,12 +224,12 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
queryParam = this.buildQueryParams(this.state.dQuery, query);
|
||||
let url = `${this.props.siteUrl}/_api/web/lists/GetByTitle('${this.props.listName}')/items/${queryParam}`;
|
||||
this.urlCollection.push(url);
|
||||
this._readItems(url);
|
||||
}
|
||||
|
||||
private _onImageClick(selectedImage: any): void {
|
||||
this.setState({
|
||||
selectedImage,
|
||||
|
@ -263,7 +239,6 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
}
|
||||
|
||||
public render(): React.ReactElement<IImageGalleryProps> {
|
||||
|
||||
const spinnerStyles = props => ({
|
||||
circle: [
|
||||
{
|
||||
|
@ -279,13 +254,11 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
]
|
||||
});
|
||||
|
||||
|
||||
let result = [];
|
||||
|
||||
let tagList;
|
||||
|
||||
if (this.state.items.length) {
|
||||
|
||||
result = this.state.items.map((item, index) => {
|
||||
return (
|
||||
<div key={index} className={css(styles.column, styles.mslg3)} onClick={() => this._onImageClick(item)}>
|
||||
|
@ -295,27 +268,27 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
<figcaption>{item.Title}</figcaption>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (objectDefinedNotNull(this.state.selectedImage.Department)) {
|
||||
if (this.state.selectedImage.Department) {
|
||||
tagList = this.state.selectedImage.Department.map((tag: any, index) => {
|
||||
return <li className={styles.listGroupItem} key={index}> <Icon iconName="Tag" className={styles.msIconTag} /> {tag.Label}</li>;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.imageGallery}>
|
||||
<div className={styles.container} dir="ltr">
|
||||
<div className={css(styles.row, styles.header)}>
|
||||
<div className={css(styles.column, styles.mslg12, styles.pageTitle)}>
|
||||
<h1>Image Gallery <small> Filterable</small></h1></div>
|
||||
|
||||
</div>
|
||||
<div className={css(styles.row, styles.filters)}>
|
||||
<div className={css(styles.column, styles.mslg12, styles.panel)}>
|
||||
<div className={styles.panelBody}>
|
||||
<div className={css(styles.column, styles.mslg3, styles.filter)}>
|
||||
<div className={styles.filterContainer}>
|
||||
<div>
|
||||
<TaxonomyPicker
|
||||
allowMultipleSelections={false}
|
||||
termsetNameOrID="Departments"
|
||||
|
@ -325,10 +298,9 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
onChange={this._onTaxPickerChange}
|
||||
isTermSetSelectable={false}
|
||||
/>
|
||||
|
||||
</div>
|
||||
<div className={css(styles.column, styles.mslg3, "ms-u-lgPush6", styles.searchBox)}>
|
||||
<TextField label="Search" className={styles.searchBoxInputField} placeholder="Enter search term" onChanged={this._onSearchChange} />
|
||||
<div>
|
||||
<TextField label="Search" className={styles.searchBoxInputField} placeholder="Enter search term" onChange={this._onSearchChange} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -336,15 +308,12 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
<div className={css(styles.row)}>
|
||||
<div className={css(styles.column, styles.mslg12, styles.panel)}>
|
||||
<div className={styles.panelBody}>
|
||||
|
||||
{
|
||||
this.state.showLoader
|
||||
? <Spinner size={SpinnerSize.large} label="loading..." className={css(styles.loader)} getStyles={spinnerStyles} />
|
||||
? <Spinner size={SpinnerSize.large} label="loading..." className={css(styles.loader)} styles={spinnerStyles} />
|
||||
: ""
|
||||
}
|
||||
|
||||
<div className={css(styles.row, styles.mainContent)}>
|
||||
|
||||
{result.length > 0 ? result : ""}
|
||||
{!result.length && this.state.itemsNotFound ? <MessageBar
|
||||
messageBarType={MessageBarType.warning}
|
||||
|
@ -375,7 +344,6 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -386,10 +354,10 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
<div className={styles.status}>{this.state.status}</div>
|
||||
<ul className={styles.pager}>
|
||||
<li>
|
||||
<Button disabled={((this.state.currentPage - 1) * this.props.pageSize + 1) <= 1} onClick={this._onClickPrevious}>Previous</Button>
|
||||
<PrimaryButton disabled={((this.state.currentPage - 1) * this.props.pageSize + 1) <= 1} onClick={this._onClickPrevious}>Previous</PrimaryButton>
|
||||
</li>
|
||||
<li>
|
||||
<Button disabled={((this.state.currentPage - 1) * this.props.pageSize) + this.state.items.length >= this.state.itemCount} onClick={this._onClickNext}>Next</Button>
|
||||
<PrimaryButton disabled={((this.state.currentPage - 1) * this.props.pageSize) + this.state.items.length >= this.state.itemCount} onClick={this._onClickNext}>Next</PrimaryButton>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
@ -399,5 +367,4 @@ export default class ImageGallery extends React.Component<IImageGalleryProps, II
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 542 B |
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.9/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
@ -10,25 +11,25 @@
|
|||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
{
|
||||
"rulesDirectory": [
|
||||
"tslint-microsoft-contrib"
|
||||
],
|
||||
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
|
@ -19,7 +17,6 @@
|
|||
"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,
|
||||
|
|
Loading…
Reference in New Issue