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 pagination
* Group items by any field
* Cache to retreive the items
* Cache to retrieve the items
* Get section color
* Show item count with custom message
#### Merge items from different lists/libraries
![](assets/differentSources.gif)
![Merge items from different lists/libraries](assets/differentSources.gif)
#### Select render of the selected fields
![](assets/selectFieldRenderType.gif)
![Select render of the selected fields](assets/selectFieldRenderType.gif)
#### Open documents in modal window
![](assets/docInModal.gif)
![Open documents in modal window](assets/docInModal.gif)
#### Open documents in new tab
![](assets/docInNewTab.gif)
![Open documents in new tab](assets/docInNewTab.gif)
#### Use of dynamic data
![](assets/dynamicData.gif)
![Use of dynamic data](assets/dynamicData.gif)
#### Open selected item with same data
![](assets/itemCurrentData.gif)
![Open selected item with same data](assets/itemCurrentData.gif)
#### 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
![](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
@ -76,28 +90,30 @@ Version|Date|Comments
## Minimal Path to Awesome
### Dev Mode
* Clone this repository
* In the command line run:
* Navigate to list-search-webpart
* Navigate to `list-search-webpart`
* `npm install`
* `gulp serve`
* Open the *workbench* on your Office 365 Developer tenant
* Test out the web part
### Sppkg
* Download sppkg files from sppkg folder
* Upload files to App Catalog
* Download `.sppkg` files from `sppkg` folder
* Upload files to **App Catalog**
## Features
This Web Part illustrates the following concepts on top of the SharePoint Framework:
* 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
* 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)
* [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" />

View File

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

View File

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

View File

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

View File

@ -1,36 +1,36 @@
'use strict';
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.`);
const argv = build.rig.getYargs().argv;
const useCustomServe = argv['custom-serve'];
const fs = require("fs");
const workbenchApi = require("@microsoft/sp-webpart-workbench/lib/api");
if (useCustomServe) {
build.tslintCmd.enabled = false;
const ensureWorkbenchSubtask = build.subTask('ensure-workbench-task', function (gulp, buildOptions, done) {
this.log('Creating workbench.html file...');
try {
workbenchApi.default["/workbench"]();
} catch (e) { }
done();
});
build.rig.addPostBuildTask(build.task('ensure-workbench', ensureWorkbenchSubtask));
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
fs.writeFileSync("./temp/_webpack_config.json", JSON.stringify(generatedConfiguration, null, 2));
return generatedConfiguration;
}
});
}
build.initialize(require('gulp'));
'use strict';
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.`);
const argv = build.rig.getYargs().argv;
const useCustomServe = argv['custom-serve'];
const fs = require("fs");
const workbenchApi = require("@microsoft/sp-webpart-workbench/lib/api");
if (useCustomServe) {
build.tslintCmd.enabled = false;
const ensureWorkbenchSubtask = build.subTask('ensure-workbench-task', function (gulp, buildOptions, done) {
this.log('Creating workbench.html file...');
try {
workbenchApi.default["/workbench"]();
} catch (e) { }
done();
});
build.rig.addPostBuildTask(build.task('ensure-workbench', ensureWorkbenchSubtask));
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
fs.writeFileSync("./temp/_webpack_config.json", JSON.stringify(generatedConfiguration, null, 2));
return generatedConfiguration;
}
});
}
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",
ListSelector: "List to get the data",
ListSelectorLabel: "Select source lists",
ListSelectorPanelHeader: "Configure lists and queries to retreive data",
ListSelectorPanelHeader: "Configure lists and queries to retrieve data",
CollectionDataSiteCollectionTitle: "Site Collection",
CollectionDataListTitle: "List",
CollectionDataListViewNameTitle: "List View Title",
CollectionDataListCamlQueryTitle: "Caml Query",
CollectionDataListCamlQueryPlaceHolder: "Empty - all elemets",
CollectionDataListCamlQueryTitle: "CAML Query",
CollectionDataListCamlQueryPlaceHolder: "Empty - all elements",
GeneralPropertiesShowItemCount: "Show item count",
GeneralPropertiesRowLimitLabel: "Item limit to show",
GeneralPropertiesRowLimitDescription: "If 0 all items are render",
@ -19,9 +19,9 @@ define([], function () {
GeneralPropertiesGroupByField: "Group elements",
FieldPropertiesGroup: "Fields",
CollectionDataFieldsProperties: "Lists Field Properties",
CollectionDataFieldsToRetreive: "Fields to retreive",
CollectionDataFieldsToRetreive: "Fields to retrieve",
CollectionDataFieldsSelectBtn: "Select fields",
CollectionDataFieldsHeader: "Select fields to retreive and their mapping",
CollectionDataFieldsHeader: "Select fields to retrieve and their mapping",
CollectionDataFieldsSiteCollection: "Site Collection",
CollectionDataFieldsList: "List",
CollectionDataFieldsListField: "List Field",
@ -51,12 +51,12 @@ define([], function () {
GeneralFieldsPropertiesListDisplayName: "List column display name",
GeneralFieldsPropertiesListDisplayNameOrder: "List column display name order",
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",
GeneralFieldsPropertiesSiteProperty: "Site property to display",
GeneralFieldsPropertiesSiteDisplayNameOrder: "Site column display name order",
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",
FilterPropertiesIndividualFilterPostion: "Individual filters position",
FilterPropertiesClearAllBtnText: "Clear all button text",
@ -67,7 +67,7 @@ define([], function () {
ListSearchLoading: "Loading...",
StoragePropertiesGroupName: "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",
OnClickSimpleModalText: "Modal with current data",
OnClickCompleteModalText: "Modal with all item fields",
@ -82,7 +82,7 @@ define([], function () {
CompleteModalButton: "Configure modal fields",
CompleteModalFieldsSiteCollection: "Site Collection",
CompleteModalFieldsList: "List",
CompleteModalFieldsListField: "Soruce Field",
CompleteModalFieldsListField: "Source Field",
CompleteModalFieldsTargetField: "Display field title",
redirectDataFieldSelector: "Select urls to redirect",
redirectDataHeaderSelector: "For each list select the url to redirect",
@ -93,7 +93,7 @@ define([], function () {
OnClickNumberOfClickOptionsToSelect: "Trigger option",
OneClickTriggerText: "One click",
TwoClickTriggerText: "Two clicks",
InformationPropertiesGroupName: "Webpart Information",
InformationPropertiesGroupName: "Web part Information",
AboutPropertiesGroupName: "About",
OnClickPropertiesGroup: "On click Properties",
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",
"id": "306e0650-db3c-443a-a698-12be6e6de1ad",
"alias": "ListSearchConsumerWebPartWebPart",
"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,
"supportedHosts": ["SharePointWebPart"],
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "ListSearchConsumerWebPart" },
"description": { "default": "List Search consumer example" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "ListSearchConsumerWebPart"
}
}]
}
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "306e0650-db3c-443a-a698-12be6e6de1ad",
"alias": "ListSearchConsumerWebPartWebPart",
"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,
"supportedHosts": ["SharePointWebPart"],
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "ListSearchConsumerWebPart" },
"description": { "default": "List Search consumer example" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "ListSearchConsumerWebPart"
}
}]
}

View File

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

View File

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

View File

@ -1,34 +1,34 @@
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.listSearchConsumerWebPart {
margin: 5px;
background-color: $ms-color-themePrimary;
color: $ms-color-white;
@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);
.row {
@include ms-Grid-row;
}
.column {
@include ms-Grid-col;
@include ms-lg12;
@include ms-sm12;
}
.title {
@include ms-font-xl;
}
.subTitle {
@include ms-font-l;
}
.description {
@include ms-font-l;
}
.value {
@include ms-font-m;
}
}
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.listSearchConsumerWebPart {
margin: 5px;
background-color: $ms-color-themePrimary;
color: $ms-color-white;
@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);
.row {
@include ms-Grid-row;
}
.column {
@include ms-Grid-col;
@include ms-lg12;
@include ms-sm12;
}
.title {
@include ms-font-xl;
}
.subTitle {
@include ms-font-l;
}
.description {
@include ms-font-l;
}
.value {
@include ms-font-m;
}
}

View File

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

View File

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

View File

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

View File

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