Fixed spelling mistakes and updated README

This commit is contained in:
Hugo Bernier 2021-02-10 23:59:54 -05:00
parent db37947b7b
commit 0c8c8b62a7
55 changed files with 593 additions and 651 deletions

View File

@ -18,37 +18,51 @@ This list search web part allows the user to show data from lists or libraries.
* Item limit to show * Item limit to show
* Item pagination * Item pagination
* Group items by any field * Group items by any field
* Cache to retreive the items * Cache to retrieve the items
* Get section color * Get section color
* Show item count with custom message * Show item count with custom message
#### Merge items from different lists/libraries #### Merge items from different lists/libraries
![](assets/differentSources.gif)
![Merge items from different lists/libraries](assets/differentSources.gif)
#### Select render of the selected fields #### Select render of the selected fields
![](assets/selectFieldRenderType.gif)
![Select render of the selected fields](assets/selectFieldRenderType.gif)
#### Open documents in modal window #### Open documents in modal window
![](assets/docInModal.gif)
![Open documents in modal window](assets/docInModal.gif)
#### Open documents in new tab #### Open documents in new tab
![](assets/docInNewTab.gif)
![Open documents in new tab](assets/docInNewTab.gif)
#### Use of dynamic data #### Use of dynamic data
![](assets/dynamicData.gif)
![Use of dynamic data](assets/dynamicData.gif)
#### Open selected item with same data #### Open selected item with same data
![](assets/itemCurrentData.gif)
![Open selected item with same data](assets/itemCurrentData.gif)
#### Open selected item with selected properties #### Open selected item with selected properties
![](assets/itemSelectedData.gif)
![Open selected item with selected properties](assets/itemSelectedData.gif)
#### Redirect to url depends on selected item #### Redirect to url depends on selected item
![](assets/redirectToUrl.gif)
## Used SharePoint Framework Version ![Redirect to url depends on selected item](assets/redirectToUrl.gif)
## Compatibility
![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
![Node.js LTS 10.x](https://img.shields.io/badge/Node.js-LTS%2010.x-green.svg)
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
![Workbench Local | Hosted](https://img.shields.io/badge/Workbench-Local%20%7C%20Hosted-green.svg)
![SPFx 1.11.0](https://img.shields.io/badge/version-1.11.0-green.svg)
## Applies to ## Applies to
@ -76,28 +90,30 @@ Version|Date|Comments
## Minimal Path to Awesome ## Minimal Path to Awesome
### Dev Mode ### Dev Mode
* Clone this repository * Clone this repository
* In the command line run: * In the command line run:
* Navigate to list-search-webpart * Navigate to `list-search-webpart`
* `npm install` * `npm install`
* `gulp serve` * `gulp serve`
* Open the *workbench* on your Office 365 Developer tenant * Open the *workbench* on your Office 365 Developer tenant
* Test out the web part * Test out the web part
### Sppkg ### Sppkg
* Download sppkg files from sppkg folder
* Upload files to App Catalog * Download `.sppkg` files from `sppkg` folder
* Upload files to **App Catalog**
## Features ## Features
This Web Part illustrates the following concepts on top of the SharePoint Framework: This Web Part illustrates the following concepts on top of the SharePoint Framework:
* Using react for building SharePoint Framework client-side web parts * Using react for building SharePoint Framework client-side web parts
* Using [PnP Js](https://pnp.github.io/pnpjs) to retreive SharePoint data * Using [PnP Js](https://pnp.github.io/pnpjs) to retrieve SharePoint data
* Using [PnP Js](https://pnp.github.io/pnpjs/odata/caching) to cache SharePoint data * Using [PnP Js](https://pnp.github.io/pnpjs/odata/caching) to cache SharePoint data
* Connection between SharePoint Framework components using dynamic data * Connection between SharePoint Framework components using dynamic data
* [Support of section backgrounds color ](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/supporting-section-backgrounds) * [Support of section backgrounds color ](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/supporting-section-backgrounds)
* [Custom property pane control](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/build-custom-property-pane-controls) * [Custom property pane control](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/build-custom-property-pane-controls)
* Use [react-js-pagination](https://www.npmjs.com/package/react-js-pagination) library * Use [react-js-pagination](https://www.npmjs.com/package/react-js-pagination) library
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-list-search" /> <img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-list-search" />

View File

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

View File

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

View File

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

View File

@ -1,36 +1,36 @@
'use strict'; 'use strict';
const build = require('@microsoft/sp-build-web'); 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.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
const argv = build.rig.getYargs().argv; const argv = build.rig.getYargs().argv;
const useCustomServe = argv['custom-serve']; const useCustomServe = argv['custom-serve'];
const fs = require("fs"); const fs = require("fs");
const workbenchApi = require("@microsoft/sp-webpart-workbench/lib/api"); const workbenchApi = require("@microsoft/sp-webpart-workbench/lib/api");
if (useCustomServe) { if (useCustomServe) {
build.tslintCmd.enabled = false; build.tslintCmd.enabled = false;
const ensureWorkbenchSubtask = build.subTask('ensure-workbench-task', function (gulp, buildOptions, done) { const ensureWorkbenchSubtask = build.subTask('ensure-workbench-task', function (gulp, buildOptions, done) {
this.log('Creating workbench.html file...'); this.log('Creating workbench.html file...');
try { try {
workbenchApi.default["/workbench"](); workbenchApi.default["/workbench"]();
} catch (e) { } } catch (e) { }
done(); done();
}); });
build.rig.addPostBuildTask(build.task('ensure-workbench', ensureWorkbenchSubtask)); build.rig.addPostBuildTask(build.task('ensure-workbench', ensureWorkbenchSubtask));
build.configureWebpack.mergeConfig({ build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => { additionalConfiguration: (generatedConfiguration) => {
fs.writeFileSync("./temp/_webpack_config.json", JSON.stringify(generatedConfiguration, null, 2)); fs.writeFileSync("./temp/_webpack_config.json", JSON.stringify(generatedConfiguration, null, 2));
return generatedConfiguration; return generatedConfiguration;
} }
}); });
} }
build.initialize(require('gulp')); build.initialize(require('gulp'));

View File

@ -1,73 +0,0 @@
# list-search-webpart
## Summary
Short summary on functionality and used technologies.
[picture of the solution in action, if possible]
## Used SharePoint Framework Version
![version](https://img.shields.io/badge/version-1.11-green.svg)
## Applies to
- [SharePoint Framework](https://aka.ms/spfx)
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
> Get your own free development tenant by subscribing to [Microsoft 365 developer program](http://aka.ms/o365devprogram)
## Prerequisites
> Any special pre-requisites?
## Solution
Solution|Author(s)
--------|---------
folder name | Author details (name, company, twitter alias with link)
## Version history
Version|Date|Comments
-------|----|--------
1.1|March 10, 2021|Update comment
1.0|January 29, 2021|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
- Ensure that you are at the solution folder
- in the command-line run:
- **npm install**
- **gulp serve**
> Include any additional steps as needed.
## Features
Description of the extension that expands upon high-level summary above.
This extension illustrates the following concepts:
- topic 1
- topic 2
- topic 3
> Notice that better pictures and documentation will increase the sample usage and the value you are providing for others. Thanks for your submissions advance.
> Share your web part with others through Microsoft 365 Patterns and Practices program to get visibility and exposure. More details on the community, open-source projects and other activities from http://aka.ms/m365pnp.
## References
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview)
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development

View File

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

View File

@ -6,12 +6,12 @@ define([], function () {
SitesSelector: "Sites to get data", SitesSelector: "Sites to get data",
ListSelector: "List to get the data", ListSelector: "List to get the data",
ListSelectorLabel: "Select source lists", ListSelectorLabel: "Select source lists",
ListSelectorPanelHeader: "Configure lists and queries to retreive data", ListSelectorPanelHeader: "Configure lists and queries to retrieve data",
CollectionDataSiteCollectionTitle: "Site Collection", CollectionDataSiteCollectionTitle: "Site Collection",
CollectionDataListTitle: "List", CollectionDataListTitle: "List",
CollectionDataListViewNameTitle: "List View Title", CollectionDataListViewNameTitle: "List View Title",
CollectionDataListCamlQueryTitle: "Caml Query", CollectionDataListCamlQueryTitle: "CAML Query",
CollectionDataListCamlQueryPlaceHolder: "Empty - all elemets", CollectionDataListCamlQueryPlaceHolder: "Empty - all elements",
GeneralPropertiesShowItemCount: "Show item count", GeneralPropertiesShowItemCount: "Show item count",
GeneralPropertiesRowLimitLabel: "Item limit to show", GeneralPropertiesRowLimitLabel: "Item limit to show",
GeneralPropertiesRowLimitDescription: "If 0 all items are render", GeneralPropertiesRowLimitDescription: "If 0 all items are render",
@ -19,9 +19,9 @@ define([], function () {
GeneralPropertiesGroupByField: "Group elements", GeneralPropertiesGroupByField: "Group elements",
FieldPropertiesGroup: "Fields", FieldPropertiesGroup: "Fields",
CollectionDataFieldsProperties: "Lists Field Properties", CollectionDataFieldsProperties: "Lists Field Properties",
CollectionDataFieldsToRetreive: "Fields to retreive", CollectionDataFieldsToRetreive: "Fields to retrieve",
CollectionDataFieldsSelectBtn: "Select fields", CollectionDataFieldsSelectBtn: "Select fields",
CollectionDataFieldsHeader: "Select fields to retreive and their mapping", CollectionDataFieldsHeader: "Select fields to retrieve and their mapping",
CollectionDataFieldsSiteCollection: "Site Collection", CollectionDataFieldsSiteCollection: "Site Collection",
CollectionDataFieldsList: "List", CollectionDataFieldsList: "List",
CollectionDataFieldsListField: "List Field", CollectionDataFieldsListField: "List Field",
@ -51,12 +51,12 @@ define([], function () {
GeneralFieldsPropertiesListDisplayName: "List column display name", GeneralFieldsPropertiesListDisplayName: "List column display name",
GeneralFieldsPropertiesListDisplayNameOrder: "List column display name order", GeneralFieldsPropertiesListDisplayNameOrder: "List column display name order",
GeneralFieldsPropertiesListDisplayNameOrderDescription: "Order of list display name column", GeneralFieldsPropertiesListDisplayNameOrderDescription: "Order of list display name column",
GeneralFieldsPropertiesListDisplayNameSearcheable: "List title searcheable in general filter", GeneralFieldsPropertiesListDisplayNameSearcheable: "List title searchable in general filter",
GeneralFieldsPropertiesSiteDisplayName: "Site column display name", GeneralFieldsPropertiesSiteDisplayName: "Site column display name",
GeneralFieldsPropertiesSiteProperty: "Site property to display", GeneralFieldsPropertiesSiteProperty: "Site property to display",
GeneralFieldsPropertiesSiteDisplayNameOrder: "Site column display name order", GeneralFieldsPropertiesSiteDisplayNameOrder: "Site column display name order",
GeneralFieldsPropertiesSiteDisplayNameOrderDescription: "Order of site display name column", GeneralFieldsPropertiesSiteDisplayNameOrderDescription: "Order of site display name column",
GeneralFieldsPropertiesSiteDisplayNameSearcheable: "Site column searcheable in general filter", GeneralFieldsPropertiesSiteDisplayNameSearcheable: "Site column searchable in general filter",
FilterPropertiesGeneralFilterPlaceHolder: "General filter placeholder", FilterPropertiesGeneralFilterPlaceHolder: "General filter placeholder",
FilterPropertiesIndividualFilterPostion: "Individual filters position", FilterPropertiesIndividualFilterPostion: "Individual filters position",
FilterPropertiesClearAllBtnText: "Clear all button text", FilterPropertiesClearAllBtnText: "Clear all button text",
@ -67,7 +67,7 @@ define([], function () {
ListSearchLoading: "Loading...", ListSearchLoading: "Loading...",
StoragePropertiesGroupName: "Cache", StoragePropertiesGroupName: "Cache",
UseLocalStorage: "Use cache", UseLocalStorage: "Use cache",
MinutesToCacheData: "Time (minutes) to cache the retreived data", MinutesToCacheData: "Time (minutes) to cache the retrieved data",
OnClickEvent: "Use on click event", OnClickEvent: "Use on click event",
OnClickSimpleModalText: "Modal with current data", OnClickSimpleModalText: "Modal with current data",
OnClickCompleteModalText: "Modal with all item fields", OnClickCompleteModalText: "Modal with all item fields",
@ -82,7 +82,7 @@ define([], function () {
CompleteModalButton: "Configure modal fields", CompleteModalButton: "Configure modal fields",
CompleteModalFieldsSiteCollection: "Site Collection", CompleteModalFieldsSiteCollection: "Site Collection",
CompleteModalFieldsList: "List", CompleteModalFieldsList: "List",
CompleteModalFieldsListField: "Soruce Field", CompleteModalFieldsListField: "Source Field",
CompleteModalFieldsTargetField: "Display field title", CompleteModalFieldsTargetField: "Display field title",
redirectDataFieldSelector: "Select urls to redirect", redirectDataFieldSelector: "Select urls to redirect",
redirectDataHeaderSelector: "For each list select the url to redirect", redirectDataHeaderSelector: "For each list select the url to redirect",
@ -93,7 +93,7 @@ define([], function () {
OnClickNumberOfClickOptionsToSelect: "Trigger option", OnClickNumberOfClickOptionsToSelect: "Trigger option",
OneClickTriggerText: "One click", OneClickTriggerText: "One click",
TwoClickTriggerText: "Two clicks", TwoClickTriggerText: "Two clicks",
InformationPropertiesGroupName: "Webpart Information", InformationPropertiesGroupName: "Web part Information",
AboutPropertiesGroupName: "About", AboutPropertiesGroupName: "About",
OnClickPropertiesGroup: "On click Properties", OnClickPropertiesGroup: "On click Properties",
GroupFieldOptionsToSelect: "Field to group by", GroupFieldOptionsToSelect: "Field to group by",

View File

@ -1,27 +1,27 @@
{ {
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", "$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "306e0650-db3c-443a-a698-12be6e6de1ad", "id": "306e0650-db3c-443a-a698-12be6e6de1ad",
"alias": "ListSearchConsumerWebPartWebPart", "alias": "ListSearchConsumerWebPartWebPart",
"componentType": "WebPart", "componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json // The "*" signifies that the version should be taken from the package.json
"version": "*", "version": "*",
"manifestVersion": 2, "manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed. // 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. // 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 // https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false, "requiresCustomScript": false,
"supportedHosts": ["SharePointWebPart"], "supportedHosts": ["SharePointWebPart"],
"preconfiguredEntries": [{ "preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other "groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" }, "group": { "default": "Other" },
"title": { "default": "ListSearchConsumerWebPart" }, "title": { "default": "ListSearchConsumerWebPart" },
"description": { "default": "List Search consumer example" }, "description": { "default": "List Search consumer example" },
"officeFabricIconFontName": "Page", "officeFabricIconFontName": "Page",
"properties": { "properties": {
"description": "ListSearchConsumerWebPart" "description": "ListSearchConsumerWebPart"
} }
}] }]
} }

View File

@ -1,98 +1,98 @@
import * as React from 'react'; import * as React from 'react';
import * as ReactDom from 'react-dom'; import * as ReactDom from 'react-dom';
import { import {
IPropertyPaneConfiguration, IPropertyPaneConfiguration,
DynamicDataSharedDepth, DynamicDataSharedDepth,
PropertyPaneDynamicFieldSet, PropertyPaneDynamicFieldSet,
PropertyPaneDynamicField PropertyPaneDynamicField
} from '@microsoft/sp-property-pane'; } from '@microsoft/sp-property-pane';
import { import {
BaseClientSideWebPart, BaseClientSideWebPart,
IWebPartPropertiesMetadata, IWebPartPropertiesMetadata,
} from '@microsoft/sp-webpart-base'; } from '@microsoft/sp-webpart-base';
import * as strings from 'ListSearchConsumerWebPartWebPartStrings'; import * as strings from 'ListSearchConsumerWebPartWebPartStrings';
import { DynamicProperty } from '@microsoft/sp-component-base'; import { DynamicProperty } from '@microsoft/sp-component-base';
import { IListSearchConsumerProps } from './components/IListSearchConsumerProps'; import { IListSearchConsumerProps } from './components/IListSearchConsumerProps';
import ListSearchConsumer from './components/ListSearchConsumerWebPart'; import ListSearchConsumer from './components/ListSearchConsumerWebPart';
export interface IListSearchConsumerWebPartProps { export interface IListSearchConsumerWebPartProps {
webUrl: DynamicProperty<string>; webUrl: DynamicProperty<string>;
listId: DynamicProperty<string>; listId: DynamicProperty<string>;
itemId: DynamicProperty<number>; itemId: DynamicProperty<number>;
} }
export default class ListSearchConsumerWebPart extends BaseClientSideWebPart<IListSearchConsumerWebPartProps> { export default class ListSearchConsumerWebPart extends BaseClientSideWebPart<IListSearchConsumerWebPartProps> {
public render(): void { public render(): void {
const element: React.ReactElement<IListSearchConsumerProps> = React.createElement( const element: React.ReactElement<IListSearchConsumerProps> = React.createElement(
ListSearchConsumer, ListSearchConsumer,
{ {
webUrl: this.properties.webUrl.tryGetValue(), webUrl: this.properties.webUrl.tryGetValue(),
listId: this.properties.listId.tryGetValue(), listId: this.properties.listId.tryGetValue(),
itemId: this.properties.itemId.tryGetValue(), itemId: this.properties.itemId.tryGetValue(),
} }
); );
ReactDom.render(element, this.domElement); ReactDom.render(element, this.domElement);
} }
protected onDispose(): void { protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement); ReactDom.unmountComponentAtNode(this.domElement);
} }
protected get propertiesMetadata(): IWebPartPropertiesMetadata { protected get propertiesMetadata(): IWebPartPropertiesMetadata {
return { return {
// Specify the web part properties data type to allow the address // Specify the web part properties data type to allow the address
// information to be serialized by the SharePoint Framework. // information to be serialized by the SharePoint Framework.
'webUrl': { 'webUrl': {
dynamicPropertyType: 'string' dynamicPropertyType: 'string'
}, },
'listId': { 'listId': {
dynamicPropertyType: 'string' dynamicPropertyType: 'string'
}, },
'itemId': { 'itemId': {
dynamicPropertyType: 'number' dynamicPropertyType: 'number'
} }
}; };
} }
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return { return {
pages: [ pages: [
{ {
header: { header: {
description: strings.PropertyPaneDescription description: strings.PropertyPaneDescription
}, },
groups: [ groups: [
{ {
groupName: strings.BasicGroupName, groupName: strings.BasicGroupName,
groupFields: [ groupFields: [
PropertyPaneDynamicFieldSet({ PropertyPaneDynamicFieldSet({
label: 'Select web Url', label: 'Select web Url',
fields: [ fields: [
PropertyPaneDynamicField('webUrl', { PropertyPaneDynamicField('webUrl', {
label: 'Web Url' label: 'Web Url'
}), }),
PropertyPaneDynamicField('listId', { PropertyPaneDynamicField('listId', {
label: 'List Id' label: 'List Id'
}), }),
PropertyPaneDynamicField('itemId', { PropertyPaneDynamicField('itemId', {
label: 'Item Id' label: 'Item Id'
}) })
], ],
sharedConfiguration: { sharedConfiguration: {
depth: DynamicDataSharedDepth.Property depth: DynamicDataSharedDepth.Property
} }
}) })
] ]
} }
] ]
} }
] ]
}; };
} }
} }

View File

@ -1,5 +1,5 @@
export interface IListSearchConsumerProps { export interface IListSearchConsumerProps {
webUrl: string; webUrl: string;
listId: string; listId: string;
itemId: number; itemId: number;
} }

View File

@ -1,34 +1,34 @@
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; @import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.listSearchConsumerWebPart { .listSearchConsumerWebPart {
margin: 5px; margin: 5px;
background-color: $ms-color-themePrimary; background-color: $ms-color-themePrimary;
color: $ms-color-white; color: $ms-color-white;
@include ms-Grid; @include ms-Grid;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
.row { .row {
@include ms-Grid-row; @include ms-Grid-row;
} }
.column { .column {
@include ms-Grid-col; @include ms-Grid-col;
@include ms-lg12; @include ms-lg12;
@include ms-sm12; @include ms-sm12;
} }
.title { .title {
@include ms-font-xl; @include ms-font-xl;
} }
.subTitle { .subTitle {
@include ms-font-l; @include ms-font-l;
} }
.description { .description {
@include ms-font-l; @include ms-font-l;
} }
.value { .value {
@include ms-font-m; @include ms-font-m;
} }
} }

View File

@ -1,32 +1,32 @@
import * as React from 'react'; import * as React from 'react';
import styles from './ListSearchConsumerWebPart.module.scss'; import styles from './ListSearchConsumerWebPart.module.scss';
import { IListSearchConsumerProps } from './IListSearchConsumerProps'; import { IListSearchConsumerProps } from './IListSearchConsumerProps';
export default class ListSearchConsumer extends React.Component<IListSearchConsumerProps, {}> { export default class ListSearchConsumer extends React.Component<IListSearchConsumerProps, {}> {
public render(): React.ReactElement<IListSearchConsumerProps> { public render(): React.ReactElement<IListSearchConsumerProps> {
return ( return (
<div className={styles.listSearchConsumerWebPart}> <div className={styles.listSearchConsumerWebPart}>
<div className={styles.row}> <div className={styles.row}>
<div className={styles.column}> <div className={styles.column}>
<span className={styles.title}>List search consumer webpart</span> <span className={styles.title}>List search consumer webpart</span>
</div> </div>
<div className={styles.column}> <div className={styles.column}>
<div className={styles.description}>WebUrl: <div className={styles.description}>WebUrl:
<p className={styles.value}>{this.props.webUrl}</p> <p className={styles.value}>{this.props.webUrl}</p>
</div> </div>
</div> </div>
<div className={styles.column}> <div className={styles.column}>
<div className={styles.description}>ListId: <div className={styles.description}>ListId:
<p className={styles.value}>{this.props.listId}</p> <p className={styles.value}>{this.props.listId}</p>
</div> </div>
</div> </div>
<div className={styles.column}> <div className={styles.column}>
<div className={styles.description}>ItemId: <div className={styles.description}>ItemId:
<p className={styles.value}>{this.props.itemId}</p> <p className={styles.value}>{this.props.itemId}</p>
</div> </div>
</div> </div>
</div> </div>
</div > </div >
); );
} }
} }

View File

@ -1,7 +1,7 @@
define([], function() { define([], function() {
return { return {
"PropertyPaneDescription": "Description", "PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name", "BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field" "DescriptionFieldLabel": "Description Field"
} }
}); });

View File

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

View File

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

View File

@ -1,259 +1,259 @@
const path = require("path"); const path = require("path");
const fs = require("fs"); const fs = require("fs");
const webpack = require("webpack"); const webpack = require("webpack");
const resolve = require("path").resolve; const resolve = require("path").resolve;
const CertStore = require("@microsoft/gulp-core-build-serve/lib/CertificateStore"); const CertStore = require("@microsoft/gulp-core-build-serve/lib/CertificateStore");
const CertificateStore = CertStore.CertificateStore || CertStore.default; const CertificateStore = CertStore.CertificateStore || CertStore.default;
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const del = require("del"); const del = require("del");
const port = 4321; const port = 4321;
const host = "https://localhost:" + port; const host = "https://localhost:" + port;
/// ///
// Transforms define("<guid>", ...) to web part specific define("<web part id_version", ...) // Transforms define("<guid>", ...) to web part specific define("<web part id_version", ...)
// the same approach is used inside copyAssets SPFx build step // the same approach is used inside copyAssets SPFx build step
/// ///
class DynamicLibraryPlugin { class DynamicLibraryPlugin {
constructor(options) { constructor(options) {
this.opitons = options; this.opitons = options;
} }
apply(compiler) { apply(compiler) {
compiler.hooks.emit.tap("DynamicLibraryPlugin", compilation => { compiler.hooks.emit.tap("DynamicLibraryPlugin", compilation => {
for (const assetId in this.opitons.modulesMap) { for (const assetId in this.opitons.modulesMap) {
const moduleMap = this.opitons.modulesMap[assetId]; const moduleMap = this.opitons.modulesMap[assetId];
if (compilation.assets[assetId]) { if (compilation.assets[assetId]) {
const rawValue = compilation.assets[assetId].children[0]._value; const rawValue = compilation.assets[assetId].children[0]._value;
compilation.assets[assetId].children[0]._value = rawValue.replace(this.opitons.libraryName, moduleMap.id + "_" + moduleMap.version); compilation.assets[assetId].children[0]._value = rawValue.replace(this.opitons.libraryName, moduleMap.id + "_" + moduleMap.version);
} }
} }
}); });
} }
} }
/// ///
// Removes *.module.scss.ts on the first execution in order prevent conflicts with *.module.scss.d.ts // Removes *.module.scss.ts on the first execution in order prevent conflicts with *.module.scss.d.ts
// generated by css-modules-typescript-loader // generated by css-modules-typescript-loader
/// ///
class ClearCssModuleDefinitionsPlugin { class ClearCssModuleDefinitionsPlugin {
constructor(options) { constructor(options) {
this.options = options || {}; this.options = options || {};
} }
apply(compiler) { apply(compiler) {
compiler.hooks.done.tap("FixStylesPlugin", stats => { compiler.hooks.done.tap("FixStylesPlugin", stats => {
if (!this.options.deleted) { if (!this.options.deleted) {
setTimeout(() => { setTimeout(() => {
del.sync(["src/**/*.module.scss.ts"]); del.sync(["src/**/*.module.scss.ts"]);
}, 3000); }, 3000);
this.options.deleted = true; this.options.deleted = true;
} }
}); });
} }
} }
let baseConfig = { let baseConfig = {
target: "web", target: "web",
mode: "development", mode: "development",
devtool: "source-map", devtool: "source-map",
resolve: { resolve: {
extensions: [".ts", ".tsx", ".js"], extensions: [".ts", ".tsx", ".js"],
modules: ["node_modules"] modules: ["node_modules"]
}, },
context: path.resolve(__dirname), context: path.resolve(__dirname),
module: { module: {
rules: [ rules: [
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
loader: "ts-loader", loader: "ts-loader",
options: { options: {
transpileOnly: true, transpileOnly: true,
compilerOptions: { compilerOptions: {
declarationMap: false declarationMap: false
} }
}, },
exclude: /node_modules/ exclude: /node_modules/
}, },
{ {
use: [{ use: [{
loader: "@microsoft/loader-cased-file", loader: "@microsoft/loader-cased-file",
options: { options: {
name: "[name:lower]_[hash].[ext]" name: "[name:lower]_[hash].[ext]"
} }
}], }],
test: /\.(jpe?g|png|woff|eot|ttf|svg|gif|dds)$/i test: /\.(jpe?g|png|woff|eot|ttf|svg|gif|dds)$/i
}, },
{ {
use: [{ use: [{
loader: "html-loader" loader: "html-loader"
}], }],
test: /\.html$/ test: /\.html$/
}, },
{ {
test: /\.css$/, test: /\.css$/,
use: [ use: [
{ {
loader: "@microsoft/loader-load-themed-styles", loader: "@microsoft/loader-load-themed-styles",
options: { options: {
async: true async: true
} }
}, },
{ {
loader: "css-loader" loader: "css-loader"
} }
] ]
}, },
{ {
test: function (fileName) { test: function (fileName) {
return fileName.endsWith(".module.scss"); // scss modules support return fileName.endsWith(".module.scss"); // scss modules support
}, },
use: [ use: [
{ {
loader: "@microsoft/loader-load-themed-styles", loader: "@microsoft/loader-load-themed-styles",
options: { options: {
async: true async: true
} }
}, },
"css-modules-typescript-loader", "css-modules-typescript-loader",
{ {
loader: "css-loader", loader: "css-loader",
options: { options: {
modules: { modules: {
localIdentName: "[local]_[hash:base64:8]" localIdentName: "[local]_[hash:base64:8]"
} }
} }
}, // translates CSS into CommonJS }, // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default "sass-loader" // compiles Sass to CSS, using Node Sass by default
] ]
}, },
{ {
test: function (fileName) { test: function (fileName) {
return !fileName.endsWith(".module.scss") && fileName.endsWith(".scss"); // just regular .scss return !fileName.endsWith(".module.scss") && fileName.endsWith(".scss"); // just regular .scss
}, },
use: [ use: [
{ {
loader: "@microsoft/loader-load-themed-styles", loader: "@microsoft/loader-load-themed-styles",
options: { options: {
async: true async: true
} }
}, },
"css-loader", // translates CSS into CommonJS "css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default "sass-loader" // compiles Sass to CSS, using Node Sass by default
] ]
} }
] ]
}, },
plugins: [ plugins: [
new ForkTsCheckerWebpackPlugin({ new ForkTsCheckerWebpackPlugin({
tslint: true tslint: true
}), }),
new ClearCssModuleDefinitionsPlugin(), new ClearCssModuleDefinitionsPlugin(),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
"process.env.DEBUG": JSON.stringify(true), "process.env.DEBUG": JSON.stringify(true),
"DEBUG": JSON.stringify(true) "DEBUG": JSON.stringify(true)
})], })],
devServer: { devServer: {
hot: false, hot: false,
contentBase: resolve(__dirname), contentBase: resolve(__dirname),
publicPath: host + "/dist/", publicPath: host + "/dist/",
host: "localhost", host: "localhost",
port: port, port: port,
disableHostCheck: true, disableHostCheck: true,
historyApiFallback: true, historyApiFallback: true,
open: true, open: true,
writeToDisk: false, writeToDisk: false,
openPage: host + "/temp/workbench.html", openPage: host + "/temp/workbench.html",
stats: { stats: {
preset: "errors-only", preset: "errors-only",
colors: true, colors: true,
chunks: false, chunks: false,
modules: false, modules: false,
assets: false assets: false
}, },
proxy: { // url re-write for resources to be served directly from src folder proxy: { // url re-write for resources to be served directly from src folder
"/lib/**/loc/*.js": { "/lib/**/loc/*.js": {
target: host, target: host,
pathRewrite: { "^/lib": "/src" }, pathRewrite: { "^/lib": "/src" },
secure: false secure: false
} }
}, },
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
}, },
https: { https: {
cert: CertificateStore.instance.certificateData, cert: CertificateStore.instance.certificateData,
key: CertificateStore.instance.keyData key: CertificateStore.instance.keyData
} }
}, },
} }
const createConfig = function () { const createConfig = function () {
// remove old css module TypeScript definitions // remove old css module TypeScript definitions
del.sync(["dist/*.js", "dist/*.map"]); del.sync(["dist/*.js", "dist/*.map"]);
// we need only "externals", "output" and "entry" from the original webpack config // we need only "externals", "output" and "entry" from the original webpack config
let originalWebpackConfig = require("./temp/_webpack_config.json"); let originalWebpackConfig = require("./temp/_webpack_config.json");
baseConfig.externals = originalWebpackConfig.externals; baseConfig.externals = originalWebpackConfig.externals;
baseConfig.output = originalWebpackConfig.output; baseConfig.output = originalWebpackConfig.output;
baseConfig.entry = getEntryPoints(originalWebpackConfig.entry); baseConfig.entry = getEntryPoints(originalWebpackConfig.entry);
baseConfig.output.publicPath = host + "/dist/"; baseConfig.output.publicPath = host + "/dist/";
const manifest = require("./temp/manifests.json"); const manifest = require("./temp/manifests.json");
const modulesMap = {}; const modulesMap = {};
const originalEntries = Object.keys(originalWebpackConfig.entry); const originalEntries = Object.keys(originalWebpackConfig.entry);
for (const jsModule of manifest) { for (const jsModule of manifest) {
if (jsModule.loaderConfig if (jsModule.loaderConfig
&& jsModule.loaderConfig.entryModuleId && jsModule.loaderConfig.entryModuleId
&& originalEntries.indexOf(jsModule.loaderConfig.entryModuleId) !== -1) { && originalEntries.indexOf(jsModule.loaderConfig.entryModuleId) !== -1) {
modulesMap[jsModule.loaderConfig.entryModuleId + ".js"] = { modulesMap[jsModule.loaderConfig.entryModuleId + ".js"] = {
id: jsModule.id, id: jsModule.id,
version: jsModule.version version: jsModule.version
} }
} }
} }
baseConfig.plugins.push(new DynamicLibraryPlugin({ baseConfig.plugins.push(new DynamicLibraryPlugin({
modulesMap: modulesMap, modulesMap: modulesMap,
libraryName: originalWebpackConfig.output.library libraryName: originalWebpackConfig.output.library
})); }));
return baseConfig; return baseConfig;
} }
function getEntryPoints(entry) { function getEntryPoints(entry) {
// fix: ".js" entry needs to be ".ts" // fix: ".js" entry needs to be ".ts"
// also replaces the path form /lib/* to /src/* // also replaces the path form /lib/* to /src/*
let newEntry = {}; let newEntry = {};
let libSearchRegexp; let libSearchRegexp;
if (path.sep === "/") { if (path.sep === "/") {
libSearchRegexp = /\/lib\//gi; libSearchRegexp = /\/lib\//gi;
} else { } else {
libSearchRegexp = /\\lib\\/gi; libSearchRegexp = /\\lib\\/gi;
} }
const srcPathToReplace = path.sep + "src" + path.sep; const srcPathToReplace = path.sep + "src" + path.sep;
for (const key in entry) { for (const key in entry) {
let entryPath = entry[key]; let entryPath = entry[key];
if (entryPath.indexOf("bundle-entries") === -1) { if (entryPath.indexOf("bundle-entries") === -1) {
entryPath = entryPath.replace(libSearchRegexp, srcPathToReplace).slice(0, -3) + ".ts"; entryPath = entryPath.replace(libSearchRegexp, srcPathToReplace).slice(0, -3) + ".ts";
} else { } else {
// replace paths and extensions in bundle file // replace paths and extensions in bundle file
let bundleContent = fs.readFileSync(entryPath).toString(); let bundleContent = fs.readFileSync(entryPath).toString();
bundleContent = bundleContent.replace(libSearchRegexp, srcPathToReplace).replace(/\.js/gi, ".ts"); bundleContent = bundleContent.replace(libSearchRegexp, srcPathToReplace).replace(/\.js/gi, ".ts");
fs.writeFileSync(entryPath, bundleContent); fs.writeFileSync(entryPath, bundleContent);
} }
newEntry[key] = entryPath; newEntry[key] = entryPath;
} }
return newEntry; return newEntry;
} }
module.exports = createConfig(); module.exports = createConfig();