Updated to drop 1.4, fixed property pane issues, and added more settings (#393)
* Updated to SPFx Drop 1.4 * Store last query in order to update the results when changing the search properties. * Bugfix: Make sure selected properties are passed along and updated on each search query. * Support more properties for preview image depending on item type. * Moved default values to web part config instead of hard coded in the web part. * Added support to show/hide file icon per result * Remove empty check for query template as it's not required, but optional. * Don't render filter control if there are no refiners specified. * Added support to show/hide the created date field. * Added more default properties for default image preview * Updated preview image based on new properties * Updated version to 1.1 Updated readme with new version, author and drop
This commit is contained in:
parent
14f6753b62
commit
cf1d8d40de
|
@ -10,7 +10,7 @@ This sample shows you how to build user friendly SharePoint search experiences u
|
|||
An associated [blog post](http://thecollaborationcorner.com/2017/10/16/build-dynamic-sharepoint-search-experiences-with-refiners-and-paging-with-spfx-office-ui-fabric-and-pnp-js-library/) is available to give you more details about this sample implementation.
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-1.3.4-green.svg)
|
||||
![drop](https://img.shields.io/badge/drop-1.4.0-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
|
@ -21,13 +21,14 @@ An associated [blog post](http://thecollaborationcorner.com/2017/10/16/build-dyn
|
|||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-search-refiners | Franck Cornu (MVP Office Development at aequos) - Twitter @FranckCornu
|
||||
react-search-refiners | Franck Cornu (MVP Office Development at aequos) - [@FranckCornu](http://www.twitter.com/FranckCornu)<br/>Mikael Svenson -[@mikaelsvenson](http://www.twitter.com/mikaelsvenson)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0 | January 03, 2018 | Initial release
|
||||
1.0 | October 17, 2017 | Initial release
|
||||
1.1 | January 03, 2018 | Improvements and updating to SPFx drop 1.4
|
||||
|
||||
## 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.**
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
"solution": {
|
||||
"name": "PnP - Search and Refiners Web Part",
|
||||
"id": "890affef-33e0-4d72-bd72-36399e02143b",
|
||||
"version": "1.0.0.0"
|
||||
"version": "1.1.0.0",
|
||||
"includeClientSideAssets": true
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/pnp-react-search-refiners.sppkg"
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 26 KiB |
|
@ -11,31 +11,31 @@
|
|||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "~1.3.4",
|
||||
"@microsoft/sp-lodash-subset": "~1.3.4",
|
||||
"@microsoft/sp-webpart-base": "~1.3.4",
|
||||
"@pnp/spfx-controls-react": "^1.0.0-beta.8",
|
||||
"@pnp/spfx-property-controls": "1.0.0",
|
||||
"@types/react": "15.0.38",
|
||||
"@microsoft/sp-core-library": "~1.4.0",
|
||||
"@microsoft/sp-lodash-subset": "~1.4.0",
|
||||
"@microsoft/sp-webpart-base": "~1.4.0",
|
||||
"@pnp/spfx-controls-react": "^1.1.1",
|
||||
"@pnp/spfx-property-controls": "^1.1.1",
|
||||
"@types/react": "15.6.6",
|
||||
"@types/react-addons-shallow-compare": "0.14.17",
|
||||
"@types/react-addons-test-utils": "0.14.15",
|
||||
"@types/react-addons-update": "0.14.14",
|
||||
"@types/react-dom": "0.14.18",
|
||||
"@types/react-dom": "15.5.6",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"immutability-helper": "2.4.0",
|
||||
"lodash-es": "4.17.4",
|
||||
"moment": "2.18.1",
|
||||
"office-ui-fabric-react": "4.40.2-hotfix.1",
|
||||
"react": "15.4.2",
|
||||
"react": "15.6.2",
|
||||
"react-custom-scrollbars": "4.1.2",
|
||||
"react-dom": "15.4.2",
|
||||
"react-dom": "15.6.2",
|
||||
"react-js-pagination": "3.0.0",
|
||||
"sp-pnp-js": "3.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.3.4",
|
||||
"@microsoft/sp-module-interfaces": "~1.3.4",
|
||||
"@microsoft/sp-webpart-workbench": "~1.3.4",
|
||||
"@microsoft/sp-build-web": "~1.4.0",
|
||||
"@microsoft/sp-module-interfaces": "~1.4.0",
|
||||
"@microsoft/sp-webpart-workbench": "~1.4.0",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0"
|
||||
|
|
|
@ -5,4 +5,6 @@ export interface ISearchWebPartProps {
|
|||
selectedProperties: string;
|
||||
refiners: string;
|
||||
showPaging: boolean;
|
||||
showFileIcon: boolean;
|
||||
showCreatedDate: boolean;
|
||||
}
|
||||
|
|
|
@ -1,30 +1,37 @@
|
|||
{
|
||||
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "42ad2740-3c60-49cf-971a-c44e33511b93",
|
||||
"alias": "SearchWebPart",
|
||||
"componentType": "WebPart",
|
||||
|
||||
// The "*" signifies that the version should be taken from the package.json
|
||||
"version": "*",
|
||||
"manifestVersion": 2,
|
||||
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed.
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": { "default": "PnP" },
|
||||
"title": { "default": "Search with Refiners" },
|
||||
"description": { "default": "Displays search results with customizable dynamic refiners" },
|
||||
"officeFabricIconFontName": "Search",
|
||||
"properties": {
|
||||
"queryKeywords": "",
|
||||
"queryTemplate": "",
|
||||
"refiners": "",
|
||||
"selectedProperties": "",
|
||||
"maxResultsCount": 10
|
||||
}
|
||||
}]
|
||||
}
|
||||
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "42ad2740-3c60-49cf-971a-c44e33511b93",
|
||||
"alias": "SearchWebPart",
|
||||
"componentType": "WebPart",
|
||||
// The "*" signifies that the version should be taken from the package.json
|
||||
"version": "*",
|
||||
"manifestVersion": 2,
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed.
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": {
|
||||
"default": "PnP"
|
||||
},
|
||||
"title": {
|
||||
"default": "Search with Refiners"
|
||||
},
|
||||
"description": {
|
||||
"default": "Displays search results with customizable dynamic refiners"
|
||||
},
|
||||
"officeFabricIconFontName": "Search",
|
||||
"properties": {
|
||||
"queryKeywords": "",
|
||||
"queryTemplate": "{searchTerms} Path:{Site}",
|
||||
"refiners": "Created",
|
||||
"selectedProperties": "Title,Path,Created,Filename,SiteLogo,PreviewUrl,PictureThumbnailURL,ServerRedirectedPreviewURL",
|
||||
"maxResultsCount": 10,
|
||||
"showFileIcon": true,
|
||||
"showCreatedDate": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,11 +2,11 @@ import * as React from 'react';
|
|||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
PropertyPaneSlider,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneToggle
|
||||
BaseClientSideWebPart,
|
||||
PropertyPaneSlider,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneToggle
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
import { Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
||||
import * as strings from 'SearchWebPartStrings';
|
||||
|
@ -21,140 +21,149 @@ import { Placeholder, IPlaceholderProps } from "@pnp/spfx-controls-react/lib/Pla
|
|||
|
||||
export default class SearchWebPart extends BaseClientSideWebPart<ISearchWebPartProps> {
|
||||
|
||||
private _dataProvider: ISearchDataProvider;
|
||||
private _dataProvider: ISearchDataProvider;
|
||||
|
||||
/**
|
||||
* Override the base onInit() implementation to get the persisted properties to initialize data provider.
|
||||
*/
|
||||
protected onInit(): Promise<void> {
|
||||
/**
|
||||
* Override the base onInit() implementation to get the persisted properties to initialize data provider.
|
||||
*/
|
||||
protected onInit(): Promise<void> {
|
||||
|
||||
// Init the moment JS library locale globally
|
||||
const currentLocale = this.context.pageContext.cultureInfo.currentCultureName;
|
||||
moment.locale(currentLocale);
|
||||
// Init the moment JS library locale globally
|
||||
const currentLocale = this.context.pageContext.cultureInfo.currentCultureName;
|
||||
moment.locale(currentLocale);
|
||||
|
||||
if (Environment.type === EnvironmentType.Local) {
|
||||
this._dataProvider = new MockSearchDataProvider();
|
||||
} else {
|
||||
this._dataProvider = new SearchDataProvider(this.context);
|
||||
}
|
||||
|
||||
return super.onInit();
|
||||
}
|
||||
|
||||
protected get disableReactivePropertyChanges(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
let renderElement = null;
|
||||
|
||||
// Configure the provider before the query according to our needs
|
||||
this._dataProvider.resultsCount = this.properties.maxResultsCount;
|
||||
this._dataProvider.queryTemplate = this.properties.queryTemplate;
|
||||
|
||||
const searchContainer: React.ReactElement<ISearchContainerProps> = React.createElement(
|
||||
SearchContainer,
|
||||
{
|
||||
searchDataProvider: this._dataProvider,
|
||||
queryKeywords: this.properties.queryKeywords,
|
||||
maxResultsCount: this.properties.maxResultsCount,
|
||||
selectedProperties: this.properties.selectedProperties ? this.properties.selectedProperties.replace(/\s|,+$/g,'').split(",") :[],
|
||||
refiners: this.properties.refiners,
|
||||
showPaging: this.properties.showPaging,
|
||||
} as ISearchContainerProps
|
||||
);
|
||||
|
||||
const placeholder: React.ReactElement<IPlaceholderProps> = React.createElement(
|
||||
Placeholder,
|
||||
{
|
||||
iconName: strings.PlaceHolderEditLabel,
|
||||
iconText: strings.PlaceHolderIconText,
|
||||
description: strings.PlaceHolderDescription,
|
||||
buttonLabel: strings.PlaceHolderConfigureBtnLabel,
|
||||
onConfigure: this._setupWebPart.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
renderElement = this.properties.queryKeywords ? searchContainer : placeholder;
|
||||
|
||||
ReactDom.render(renderElement, this.domElement);
|
||||
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.SearchSettingsGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('queryKeywords', {
|
||||
label: strings.SearchQueryKeywordsFieldLabel,
|
||||
value: "",
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
placeholder: strings.SearchQueryPlaceHolderText,
|
||||
onGetErrorMessage: this._validateEmptyField.bind(this)
|
||||
}),
|
||||
PropertyPaneTextField('queryTemplate', {
|
||||
label: strings.QueryTemplateFieldLabel,
|
||||
value: "{searchTerms} Path:{Site}",
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
placeholder: strings.SearchQueryPlaceHolderText,
|
||||
onGetErrorMessage: this._validateEmptyField.bind(this)
|
||||
}),
|
||||
PropertyPaneTextField('selectedProperties', {
|
||||
label: strings.SelectedPropertiesFieldLabel,
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
value: "Title,Path,Created,Filename,ServerRedirectedPreviewURL",
|
||||
}),
|
||||
PropertyPaneTextField('refiners', {
|
||||
label: strings.RefinersFieldLabel,
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
value: "Created"
|
||||
}),
|
||||
PropertyPaneSlider("maxResultsCount", {
|
||||
label: strings.MaxResultsCount,
|
||||
max: 50,
|
||||
min: 1,
|
||||
showValue: true,
|
||||
step: 1,
|
||||
value: 50,
|
||||
}),
|
||||
PropertyPaneToggle("showPaging", {
|
||||
label: strings.ShowPagingLabel,
|
||||
checked: false,
|
||||
}),
|
||||
]
|
||||
}
|
||||
]
|
||||
if (Environment.type === EnvironmentType.Local) {
|
||||
this._dataProvider = new MockSearchDataProvider();
|
||||
} else {
|
||||
this._dataProvider = new SearchDataProvider(this.context);
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Web Part property pane
|
||||
*/
|
||||
private _setupWebPart() {
|
||||
this.context.propertyPane.open();
|
||||
}
|
||||
|
||||
private _validateEmptyField(value: string): string {
|
||||
|
||||
if (!value) {
|
||||
return strings.EmptyFieldErrorMessage;
|
||||
return super.onInit();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
protected get disableReactivePropertyChanges(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
let renderElement = null;
|
||||
|
||||
// Configure the provider before the query according to our needs
|
||||
this._dataProvider.resultsCount = this.properties.maxResultsCount;
|
||||
this._dataProvider.queryTemplate = this.properties.queryTemplate;
|
||||
|
||||
const searchContainer: React.ReactElement<ISearchContainerProps> = React.createElement(
|
||||
SearchContainer,
|
||||
{
|
||||
searchDataProvider: this._dataProvider,
|
||||
queryKeywords: this.properties.queryKeywords,
|
||||
maxResultsCount: this.properties.maxResultsCount,
|
||||
selectedProperties: this.properties.selectedProperties ? this.properties.selectedProperties.replace(/\s|,+$/g, '').split(",") : [],
|
||||
refiners: this.properties.refiners,
|
||||
showPaging: this.properties.showPaging,
|
||||
showFileIcon: this.properties.showFileIcon,
|
||||
showCreatedDate: this.properties.showCreatedDate
|
||||
} as ISearchContainerProps
|
||||
);
|
||||
|
||||
const placeholder: React.ReactElement<IPlaceholderProps> = React.createElement(
|
||||
Placeholder,
|
||||
{
|
||||
iconName: strings.PlaceHolderEditLabel,
|
||||
iconText: strings.PlaceHolderIconText,
|
||||
description: strings.PlaceHolderDescription,
|
||||
buttonLabel: strings.PlaceHolderConfigureBtnLabel,
|
||||
onConfigure: this._setupWebPart.bind(this)
|
||||
}
|
||||
);
|
||||
|
||||
renderElement = this.properties.queryKeywords ? searchContainer : placeholder;
|
||||
|
||||
ReactDom.render(renderElement, this.domElement);
|
||||
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.SearchSettingsGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('queryKeywords', {
|
||||
label: strings.SearchQueryKeywordsFieldLabel,
|
||||
value: this.properties.queryKeywords,
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
placeholder: strings.SearchQueryPlaceHolderText,
|
||||
onGetErrorMessage: this._validateEmptyField.bind(this)
|
||||
}),
|
||||
PropertyPaneTextField('queryTemplate', {
|
||||
label: strings.QueryTemplateFieldLabel,
|
||||
value: this.properties.queryTemplate,
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
placeholder: strings.SearchQueryPlaceHolderText
|
||||
}),
|
||||
PropertyPaneTextField('selectedProperties', {
|
||||
label: strings.SelectedPropertiesFieldLabel,
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
value: this.properties.selectedProperties,
|
||||
}),
|
||||
PropertyPaneTextField('refiners', {
|
||||
label: strings.RefinersFieldLabel,
|
||||
multiline: true,
|
||||
resizable: true,
|
||||
value: this.properties.refiners
|
||||
}),
|
||||
PropertyPaneSlider("maxResultsCount", {
|
||||
label: strings.MaxResultsCount,
|
||||
max: 50,
|
||||
min: 1,
|
||||
showValue: true,
|
||||
step: 1,
|
||||
value: 50,
|
||||
}),
|
||||
PropertyPaneToggle("showPaging", {
|
||||
label: strings.ShowPagingLabel,
|
||||
checked: this.properties.showPaging,
|
||||
}),
|
||||
PropertyPaneToggle("showFileIcon", {
|
||||
label: strings.ShowFileIconLabel,
|
||||
checked: this.properties.showFileIcon,
|
||||
}),
|
||||
PropertyPaneToggle("showCreatedDate", {
|
||||
label: strings.ShowCreatedDateLabel,
|
||||
checked: this.properties.showCreatedDate,
|
||||
}),
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Web Part property pane
|
||||
*/
|
||||
private _setupWebPart() {
|
||||
this.context.propertyPane.open();
|
||||
}
|
||||
|
||||
private _validateEmptyField(value: string): string {
|
||||
|
||||
if (!value) {
|
||||
return strings.EmptyFieldErrorMessage;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import IFilterPanelState from "./IFilterPanelState";
|
|||
import { PrimaryButton, DefaultButton, IButtonProps } from 'office-ui-fabric-react/lib/Button';
|
||||
import { Panel, PanelType } from 'office-ui-fabric-react/lib/Panel';
|
||||
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
|
||||
import { Toggle } from 'office-ui-fabric-react/lib/Toggle';
|
||||
import { Toggle } from 'office-ui-fabric-react/lib/Toggle';
|
||||
import * as strings from "SearchWebPartStrings";
|
||||
import { IRefinementResult, IRefinementValue, IRefinementFilter } from "../../../models/ISearchResult";
|
||||
import { Link } from 'office-ui-fabric-react/lib/Link';
|
||||
|
@ -16,11 +16,11 @@ import {
|
|||
GroupedList,
|
||||
IGroup,
|
||||
IGroupDividerProps
|
||||
} from 'office-ui-fabric-react/lib/components/GroupedList/index';
|
||||
} from 'office-ui-fabric-react/lib/components/GroupedList/index';
|
||||
import { Scrollbars } from 'react-custom-scrollbars';
|
||||
|
||||
export default class FilterPanel extends React.Component<IFilterPanelProps, IFilterPanelState> {
|
||||
|
||||
|
||||
public constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
@ -46,6 +46,8 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
let items: JSX.Element[] = [];
|
||||
let groups: IGroup[] = [];
|
||||
|
||||
if (this.props.availableFilters.length === 0) return <span />;
|
||||
|
||||
// Initialize the Office UI grouped list
|
||||
this.props.availableFilters.map((filter, i) => {
|
||||
|
||||
|
@ -59,7 +61,7 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
});
|
||||
|
||||
items.push(
|
||||
<div key= { i }>
|
||||
<div key={i}>
|
||||
<div className="filterPanel__filterProperty">
|
||||
{
|
||||
filter.Values.map((refinementValue: IRefinementValue, j) => {
|
||||
|
@ -72,14 +74,14 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
|
||||
return (
|
||||
<Checkbox
|
||||
key={ j }
|
||||
checked= { this._isInFilterSelection(currentRefinement) }
|
||||
disabled={ false }
|
||||
label={ Text.format(refinementValue.RefinementValue + " ({0})", refinementValue.RefinementCount)}
|
||||
onChange= {(ev, checked: boolean) => {
|
||||
// Every time we chek/uncheck a filter, a complete new search request is performed with current selected refiners
|
||||
checked ? this._addFilter(currentRefinement): this._removeFilter(currentRefinement);
|
||||
}} />
|
||||
key={j}
|
||||
checked={this._isInFilterSelection(currentRefinement)}
|
||||
disabled={false}
|
||||
label={Text.format(refinementValue.RefinementValue + " ({0})", refinementValue.RefinementCount)}
|
||||
onChange={(ev, checked: boolean) => {
|
||||
// Every time we chek/uncheck a filter, a complete new search request is performed with current selected refiners
|
||||
checked ? this._addFilter(currentRefinement) : this._removeFilter(currentRefinement);
|
||||
}} />
|
||||
);
|
||||
})
|
||||
}
|
||||
|
@ -91,79 +93,79 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
const renderSelectedFilters: JSX.Element[] = this.state.selectedFilters.map((filter) => {
|
||||
|
||||
return (
|
||||
<Label className="filter">
|
||||
<i className="ms-Icon ms-Icon--ClearFilter" onClick={ ()=> { this._removeFilter(filter); }}></i>
|
||||
{ filter.Value.RefinementName }
|
||||
</Label>
|
||||
<Label className="filter">
|
||||
<i className="ms-Icon ms-Icon--ClearFilter" onClick={() => { this._removeFilter(filter); }}></i>
|
||||
{filter.Value.RefinementName}
|
||||
</Label>
|
||||
);
|
||||
});
|
||||
|
||||
const renderAvailableFilters = <GroupedList
|
||||
ref='groupedList'
|
||||
items={ items }
|
||||
onRenderCell={ this._onRenderCell }
|
||||
className="filterPanel__body__group"
|
||||
groupProps={
|
||||
{
|
||||
onRenderHeader: this._onRenderHeader,
|
||||
}
|
||||
}
|
||||
groups={ groups }/>;
|
||||
const renderAvailableFilters = <GroupedList
|
||||
ref='groupedList'
|
||||
items={items}
|
||||
onRenderCell={this._onRenderCell}
|
||||
className="filterPanel__body__group"
|
||||
groupProps={
|
||||
{
|
||||
onRenderHeader: this._onRenderHeader,
|
||||
}
|
||||
}
|
||||
groups={groups} />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<DefaultButton
|
||||
className="searchWp__filterResultBtn"
|
||||
iconProps={ { iconName: 'Filter' } }
|
||||
text={ strings.FilterResultsButtonLabel }
|
||||
onClick= { this._onTogglePanel }
|
||||
/>
|
||||
{ (this.state.selectedFilters.length > 0) ?
|
||||
iconProps={{ iconName: 'Filter' }}
|
||||
text={strings.FilterResultsButtonLabel}
|
||||
onClick={this._onTogglePanel}
|
||||
/>
|
||||
{(this.state.selectedFilters.length > 0) ?
|
||||
|
||||
<div className="searchWp__selectedFilters">
|
||||
{ renderSelectedFilters }
|
||||
</div>
|
||||
: null
|
||||
<div className="searchWp__selectedFilters">
|
||||
{renderSelectedFilters}
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
<Panel
|
||||
className="filterPanel"
|
||||
isOpen={ this.state.showPanel }
|
||||
type={ PanelType.smallFixedNear }
|
||||
isBlocking={ false }
|
||||
isLightDismiss= { true }
|
||||
onDismiss={ this._onClosePanel }
|
||||
headerText={ strings.FilterPanelTitle }
|
||||
closeButtonAriaLabel='Close'
|
||||
hasCloseButton={ true }
|
||||
isOpen={this.state.showPanel}
|
||||
type={PanelType.smallFixedNear}
|
||||
isBlocking={false}
|
||||
isLightDismiss={true}
|
||||
onDismiss={this._onClosePanel}
|
||||
headerText={strings.FilterPanelTitle}
|
||||
closeButtonAriaLabel='Close'
|
||||
hasCloseButton={true}
|
||||
headerClassName="filterPanel__header"
|
||||
|
||||
onRenderBody={() => {
|
||||
|
||||
onRenderBody={() => {
|
||||
if (this.props.availableFilters.length > 0) {
|
||||
return (
|
||||
<Scrollbars style={{ height: "100%" }}>
|
||||
<div className="filterPanel__body">
|
||||
<div className="filterPanel__body__allFiltersToggle">
|
||||
<Toggle
|
||||
onText={ strings.RemoveAllFiltersLabel }
|
||||
offText={ strings.ApplyAllFiltersLabel }
|
||||
onChanged= {(checked: boolean) => {
|
||||
<Toggle
|
||||
onText={strings.RemoveAllFiltersLabel}
|
||||
offText={strings.ApplyAllFiltersLabel}
|
||||
onChanged={(checked: boolean) => {
|
||||
checked ? this._applyAllfilters() : this._removeAllFilters();
|
||||
}}
|
||||
checked= { this.state.selectedFilters.length === 0 ? false : true }
|
||||
checked={this.state.selectedFilters.length === 0 ? false : true}
|
||||
/>
|
||||
</div>
|
||||
{ renderAvailableFilters }
|
||||
{renderAvailableFilters}
|
||||
</div>
|
||||
</Scrollbars>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="filterPanel__body">
|
||||
{ strings.NoFilterConfiguredLabel }
|
||||
{strings.NoFilterConfiguredLabel}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}}>
|
||||
}}>
|
||||
</Panel>
|
||||
</div>
|
||||
);
|
||||
|
@ -171,38 +173,38 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
|
||||
private _onRenderCell(nestingDepth: number, item: any, itemIndex: number) {
|
||||
return (
|
||||
<div className="ms-Grid-row" data-selection-index={ itemIndex }>
|
||||
<div className="ms-Grid-row" data-selection-index={itemIndex}>
|
||||
<div className="ms-Grid-col ms-u-sm10 ms-u-md10 ms-u-lg10 ms-smPush1 ms-mdPush1 ms-lgPush1">
|
||||
{ item }
|
||||
</div>
|
||||
</div>
|
||||
{item}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private _onRenderHeader(props: IGroupDividerProps): JSX.Element {
|
||||
return (
|
||||
|
||||
<div className="ms-Grid-row" onClick={ () => {
|
||||
|
||||
// Update the index for expanded groups to be able to keep it open after a re-render
|
||||
const updatedExpandedGroups =
|
||||
props.group.isCollapsed ?
|
||||
update(this.state.expandedGroups, {$push: [props.group.startIndex]}) :
|
||||
update(this.state.expandedGroups, {$splice: [[this.state.expandedGroups.indexOf(props.group.startIndex), 1]]});
|
||||
|
||||
this.setState({
|
||||
expandedGroups: updatedExpandedGroups,
|
||||
});
|
||||
<div className="ms-Grid-row" onClick={() => {
|
||||
|
||||
props.onToggleCollapse(props.group);
|
||||
}}>
|
||||
// Update the index for expanded groups to be able to keep it open after a re-render
|
||||
const updatedExpandedGroups =
|
||||
props.group.isCollapsed ?
|
||||
update(this.state.expandedGroups, { $push: [props.group.startIndex] }) :
|
||||
update(this.state.expandedGroups, { $splice: [[this.state.expandedGroups.indexOf(props.group.startIndex), 1]] });
|
||||
|
||||
this.setState({
|
||||
expandedGroups: updatedExpandedGroups,
|
||||
});
|
||||
|
||||
props.onToggleCollapse(props.group);
|
||||
}}>
|
||||
<div className="ms-Grid-col ms-u-sm1 ms-u-md1 ms-u-lg1">
|
||||
<div className="header-icon">
|
||||
<i className={ props.group.isCollapsed ? "ms-Icon ms-Icon--ChevronDown" : "ms-Icon ms-Icon--ChevronUp"}></i>
|
||||
<i className={props.group.isCollapsed ? "ms-Icon ms-Icon--ChevronDown" : "ms-Icon ms-Icon--ChevronUp"}></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ms-Grid-col ms-u-sm10 ms-u-md10 ms-u-lg10">
|
||||
<div className="ms-font-l">{ props.group.name }</div>
|
||||
<div className="ms-font-l">{props.group.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -211,7 +213,7 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
private _onClosePanel() {
|
||||
this.setState({ showPanel: false });
|
||||
}
|
||||
|
||||
|
||||
private _onTogglePanel() {
|
||||
this.setState({ showPanel: !this.state.showPanel });
|
||||
}
|
||||
|
@ -219,7 +221,7 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
private _addFilter(filterToAdd: IRefinementFilter): void {
|
||||
|
||||
// Add the filter to the selected filters collection
|
||||
let newFilters = update(this.state.selectedFilters, {$push: [filterToAdd]});
|
||||
let newFilters = update(this.state.selectedFilters, { $push: [filterToAdd] });
|
||||
this._applyFilters(newFilters);
|
||||
}
|
||||
|
||||
|
@ -239,9 +241,9 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
|
||||
this.props.availableFilters.map((filter) => {
|
||||
|
||||
filter.Values.map((refinementValue: IRefinementValue, index) => {
|
||||
allFilters.push({FilterName: filter.FilterName, Value: refinementValue});
|
||||
});
|
||||
filter.Values.map((refinementValue: IRefinementValue, index) => {
|
||||
allFilters.push({ FilterName: filter.FilterName, Value: refinementValue });
|
||||
});
|
||||
});
|
||||
|
||||
this._applyFilters(allFilters);
|
||||
|
@ -256,7 +258,7 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
* @param selectedFilters The filters to apply
|
||||
*/
|
||||
private _applyFilters(selectedFilters: IRefinementFilter[]): void {
|
||||
|
||||
|
||||
// Save the selected filters
|
||||
this.setState({
|
||||
selectedFilters: selectedFilters,
|
||||
|
@ -264,15 +266,15 @@ export default class FilterPanel extends React.Component<IFilterPanelProps, IFil
|
|||
|
||||
this.props.onUpdateFilters(selectedFilters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the current filter is present in the list of the selected filters
|
||||
* @param filterToCheck The filter to check
|
||||
*/
|
||||
private _isInFilterSelection(filterToCheck: IRefinementFilter): boolean {
|
||||
|
||||
let newFilters = this.state.selectedFilters.filter((filter) => {
|
||||
return filter.Value.RefinementToken === filterToCheck.Value.RefinementToken;
|
||||
let newFilters = this.state.selectedFilters.filter((filter) => {
|
||||
return filter.Value.RefinementToken === filterToCheck.Value.RefinementToken;
|
||||
});
|
||||
|
||||
return newFilters.length === 0 ? false : true;
|
||||
|
|
|
@ -7,6 +7,8 @@ interface ISearchContainerProps {
|
|||
selectedProperties: string[];
|
||||
refiners: string;
|
||||
showPaging: boolean;
|
||||
showFileIcon: boolean;
|
||||
showCreatedDate: boolean;
|
||||
}
|
||||
|
||||
export default ISearchContainerProps;
|
|
@ -41,6 +41,11 @@ interface ISearchContainerState {
|
|||
* Indicates whether or not the componetn loads for the first time
|
||||
*/
|
||||
isComponentLoading: boolean;
|
||||
|
||||
/**
|
||||
* Keeps the last query in case you change the query in the propery panel
|
||||
*/
|
||||
lastQuery: string;
|
||||
}
|
||||
|
||||
export default ISearchContainerState;
|
|
@ -12,18 +12,16 @@ import FilterPanel from "../FilterPanel/FilterPanel";
|
|||
import Paging from "../Paging/Paging";
|
||||
import { Overlay } from "office-ui-fabric-react";
|
||||
|
||||
export default class SearchContainer extends React.Component<ISearchContainerProps,ISearchContainerState> {
|
||||
export default class SearchContainer extends React.Component<ISearchContainerProps, ISearchContainerState> {
|
||||
|
||||
public constructor(props) {
|
||||
|
||||
super(props);
|
||||
|
||||
// Set the initial state
|
||||
this.state = {
|
||||
results: {
|
||||
RefinementResults: [],
|
||||
RelevantResults: []
|
||||
},
|
||||
results: {
|
||||
RefinementResults: [],
|
||||
RelevantResults: []
|
||||
},
|
||||
selectedFilters: [],
|
||||
availableFilters: [],
|
||||
currentPage: 1,
|
||||
|
@ -31,6 +29,7 @@ export default class SearchContainer extends React.Component<ISearchContainerPro
|
|||
isComponentLoading: true,
|
||||
errorMessage: "",
|
||||
hasError: false,
|
||||
lastQuery: ""
|
||||
};
|
||||
|
||||
this._onUpdateFilters = this._onUpdateFilters.bind(this);
|
||||
|
@ -47,63 +46,64 @@ export default class SearchContainer extends React.Component<ISearchContainerPro
|
|||
|
||||
let wpContent: JSX.Element = null;
|
||||
let renderOverlay = null;
|
||||
|
||||
|
||||
if (!isComponentLoading && areResultsLoading) {
|
||||
renderOverlay = <div>
|
||||
renderOverlay = <div>
|
||||
<Overlay isDarkThemed={false} className="overlay">
|
||||
</Overlay>
|
||||
</div>;
|
||||
}
|
||||
|
||||
if (isComponentLoading) {
|
||||
wpContent = <Spinner size={ SpinnerSize.large } label={ strings.LoadingMessage } />;
|
||||
wpContent = <Spinner size={SpinnerSize.large} label={strings.LoadingMessage} />;
|
||||
} else {
|
||||
|
||||
if (hasError) {
|
||||
wpContent = <MessageBar messageBarType= { MessageBarType.error }>{ errorMessage }</MessageBar>;
|
||||
wpContent = <MessageBar messageBarType={MessageBarType.error}>{errorMessage}</MessageBar>;
|
||||
} else {
|
||||
|
||||
if (items.RelevantResults.length === 0) {
|
||||
wpContent =
|
||||
<div>
|
||||
<FilterPanel availableFilters={ this.state.availableFilters } onUpdateFilters={ this._onUpdateFilters }/>
|
||||
<div className="searchWp__noresult">{ strings.NoResultMessage }</div>
|
||||
</div>;
|
||||
} else {
|
||||
wpContent =
|
||||
|
||||
<div>
|
||||
<FilterPanel availableFilters={ this.state.availableFilters } onUpdateFilters={ this._onUpdateFilters }/>
|
||||
{ renderOverlay }
|
||||
<TilesList items={ items.RelevantResults }/>
|
||||
{ this.props.showPaging ?
|
||||
<Paging
|
||||
totalItems={ items.TotalRows }
|
||||
itemsCountPerPage={ this.props.maxResultsCount }
|
||||
onPageUpdate={ this._onPageUpdate }
|
||||
currentPage={ this.state.currentPage }/>
|
||||
wpContent =
|
||||
<div>
|
||||
<FilterPanel availableFilters={this.state.availableFilters} onUpdateFilters={this._onUpdateFilters} />
|
||||
<div className="searchWp__noresult">{strings.NoResultMessage}</div>
|
||||
</div>;
|
||||
} else {
|
||||
wpContent =
|
||||
|
||||
<div>
|
||||
<FilterPanel availableFilters={this.state.availableFilters} onUpdateFilters={this._onUpdateFilters} />
|
||||
{renderOverlay}
|
||||
<TilesList items={items.RelevantResults} showFileIcon={this.props.showFileIcon} showCreatedDate={this.props.showCreatedDate} />
|
||||
{this.props.showPaging ?
|
||||
<Paging
|
||||
totalItems={items.TotalRows}
|
||||
itemsCountPerPage={this.props.maxResultsCount}
|
||||
onPageUpdate={this._onPageUpdate}
|
||||
currentPage={this.state.currentPage} />
|
||||
: null
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="searchWp">
|
||||
{ wpContent }
|
||||
<div className="searchWp">
|
||||
{wpContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
|
||||
try {
|
||||
|
||||
|
||||
this.setState({
|
||||
areResultsLoading: true,
|
||||
});
|
||||
|
||||
this.props.searchDataProvider.selectedProperties = this.props.selectedProperties;
|
||||
|
||||
const searchResults = await this.props.searchDataProvider.search(this.props.queryKeywords, this.props.refiners, this.state.selectedFilters, this.state.currentPage);
|
||||
|
||||
// Initial filters are just set once for the filter control during the component initialization
|
||||
|
@ -114,6 +114,7 @@ export default class SearchContainer extends React.Component<ISearchContainerPro
|
|||
availableFilters: searchResults.RefinementResults,
|
||||
areResultsLoading: false,
|
||||
isComponentLoading: false,
|
||||
lastQuery: this.props.queryKeywords + this.props.searchDataProvider.queryTemplate + this.props.selectedProperties.join(',')
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
|
@ -132,18 +133,22 @@ export default class SearchContainer extends React.Component<ISearchContainerPro
|
|||
|
||||
public async componentWillReceiveProps(nextProps: ISearchContainerProps) {
|
||||
|
||||
let query = nextProps.queryKeywords + nextProps.searchDataProvider.queryTemplate + nextProps.selectedProperties.join(',');
|
||||
// New props are passed to the component when the search query has been changed
|
||||
if (this.props.refiners.toString() !== nextProps.refiners.toString()
|
||||
|| this.props.maxResultsCount !== nextProps.maxResultsCount) {
|
||||
|| this.props.maxResultsCount !== nextProps.maxResultsCount
|
||||
|| this.state.lastQuery !== query
|
||||
|| this.props.showFileIcon !== nextProps.showFileIcon
|
||||
|| this.props.showCreatedDate !== nextProps.showCreatedDate ) {
|
||||
|
||||
try {
|
||||
|
||||
// Clear selected filters on a new query or new refiners
|
||||
this.setState({
|
||||
selectedFilters: [],
|
||||
areResultsLoading: true,
|
||||
});
|
||||
|
||||
this.props.searchDataProvider.selectedProperties = nextProps.selectedProperties;
|
||||
// We reset the page number and refinement filters
|
||||
const searchResults = await this.props.searchDataProvider.search(nextProps.queryKeywords, nextProps.refiners, [], 1);
|
||||
|
||||
|
@ -151,6 +156,7 @@ export default class SearchContainer extends React.Component<ISearchContainerPro
|
|||
results: searchResults,
|
||||
availableFilters: searchResults.RefinementResults,
|
||||
areResultsLoading: false,
|
||||
lastQuery: query
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
|
|
|
@ -2,6 +2,8 @@ import { ISearchResult } from "../../../models/ISearchResult";
|
|||
|
||||
interface ITileProps {
|
||||
item: ISearchResult;
|
||||
showFileIcon: boolean;
|
||||
showCreatedDate: boolean;
|
||||
}
|
||||
|
||||
export default ITileProps;
|
|
@ -2,6 +2,8 @@ import { ISearchResult } from "../../../models/ISearchResult";
|
|||
|
||||
interface ITilesListViewProps {
|
||||
items?: ISearchResult[];
|
||||
showFileIcon: boolean;
|
||||
showCreatedDate: boolean;
|
||||
}
|
||||
|
||||
export default ITilesListViewProps;
|
|
@ -1,16 +1,17 @@
|
|||
import * as React from "react";
|
||||
import ITileProps from "./ITileProps";
|
||||
import {
|
||||
DocumentCard,
|
||||
DocumentCardActions,
|
||||
DocumentCardActivity,
|
||||
DocumentCardLocation,
|
||||
DocumentCardPreview,
|
||||
DocumentCardTitle,
|
||||
IDocumentCardPreviewProps
|
||||
DocumentCard,
|
||||
DocumentCardActions,
|
||||
DocumentCardActivity,
|
||||
DocumentCardLocation,
|
||||
DocumentCardPreview,
|
||||
DocumentCardTitle,
|
||||
IDocumentCardPreviewProps
|
||||
} from 'office-ui-fabric-react/lib/DocumentCard';
|
||||
import { ImageFit } from 'office-ui-fabric-react/lib/Image';
|
||||
import * as moment from "moment";
|
||||
import { isEmpty } from '@microsoft/sp-lodash-subset';
|
||||
import "../SearchWebPart.scss";
|
||||
|
||||
const PREVIEW_IMAGE_WIDTH: number = 204;
|
||||
|
@ -21,28 +22,36 @@ export default class Tile extends React.Component<ITileProps, null> {
|
|||
public render() {
|
||||
|
||||
const item = this.props.item;
|
||||
|
||||
|
||||
let previewSrc = "";
|
||||
if (!isEmpty(item.SiteLogo)) previewSrc = item.SiteLogo;
|
||||
else if (!isEmpty(item.PreviewUrl)) previewSrc = item.PreviewUrl;
|
||||
else if (!isEmpty(item.PictureThumbnailURL)) previewSrc = item.PictureThumbnailURL;
|
||||
else if (!isEmpty(item.ServerRedirectedPreviewURL)) previewSrc = item.ServerRedirectedPreviewURL;
|
||||
|
||||
let iconSrc = this.props.showFileIcon ? item.iconSrc : "";
|
||||
|
||||
let previewProps: IDocumentCardPreviewProps = {
|
||||
previewImages: [
|
||||
{
|
||||
url: item.ServerRedirectedURL ? item.ServerRedirectedURL : item.Path,
|
||||
previewImageSrc: item.ServerRedirectedPreviewURL,
|
||||
iconSrc: item.iconSrc,
|
||||
previewImageSrc: previewSrc,
|
||||
iconSrc: iconSrc,
|
||||
imageFit: ImageFit.cover,
|
||||
height: PREVIEW_IMAGE_HEIGHT,
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<DocumentCard onClickHref={ item.ServerRedirectedURL ? item.ServerRedirectedURL : item.Path } className="searchWp__resultCard">
|
||||
<DocumentCard onClickHref={item.ServerRedirectedURL ? item.ServerRedirectedURL : item.Path} className="searchWp__resultCard">
|
||||
<div className="searchWp__tile__iconContainer" style={{ "height": PREVIEW_IMAGE_HEIGHT }}>
|
||||
<DocumentCardPreview { ...previewProps } />
|
||||
</div>
|
||||
<DocumentCardTitle title={ item.Title } shouldTruncate={ false } />
|
||||
<div className="searchWp__tile__footer">
|
||||
<span>{ moment(item.Created).isValid() ? moment(item.Created).format("L"): null }</span>
|
||||
</div>
|
||||
<DocumentCardTitle title={item.Title} shouldTruncate={false} />
|
||||
<div className="searchWp__tile__footer" hidden={!this.props.showCreatedDate}>
|
||||
<span>{moment(item.Created).isValid() ? moment(item.Created).format("L") : null}</span>
|
||||
</div>
|
||||
</DocumentCard>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,26 +22,26 @@ export default class TilesList extends React.Component<ITilesListViewProps, null
|
|||
this._getItemCountForPage = this._getItemCountForPage.bind(this);
|
||||
this._getPageHeight = this._getPageHeight.bind(this);
|
||||
}
|
||||
|
||||
|
||||
public render() {
|
||||
|
||||
const items = this.props.items;
|
||||
|
||||
return (
|
||||
<List
|
||||
items={ items }
|
||||
getItemCountForPage={ this._getItemCountForPage }
|
||||
getPageHeight={ this._getPageHeight }
|
||||
renderedWindowsAhead={ 4 }
|
||||
return (
|
||||
<List
|
||||
items={items}
|
||||
getItemCountForPage={this._getItemCountForPage}
|
||||
getPageHeight={this._getPageHeight}
|
||||
renderedWindowsAhead={4}
|
||||
className="searchWp__list"
|
||||
onRenderCell={ (item, index) => (
|
||||
<div className="searchWp__tile"
|
||||
style={ {
|
||||
width: (100 / this._columnCount) + '%',
|
||||
} }>
|
||||
<Tile key={ index } item= { item }/>
|
||||
</div>
|
||||
)}/>
|
||||
onRenderCell={(item, index) => (
|
||||
<div className="searchWp__tile"
|
||||
style={{
|
||||
width: (100 / this._columnCount) + '%',
|
||||
}}>
|
||||
<Tile key={index} item={item} showFileIcon={this.props.showFileIcon} showCreatedDate={this.props.showCreatedDate} />
|
||||
</div>
|
||||
)} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ define([], function() {
|
|||
"ApplyAllFiltersLabel": "Apply all filters",
|
||||
"RemoveAllFiltersLabel": "Remove all filters",
|
||||
"ShowPagingLabel": "Show paging",
|
||||
"ShowFileIconLabel": "Show file icons",
|
||||
"ShowCreatedDateLabel": "Show created date",
|
||||
"NoFilterConfiguredLabel": "No filter configured",
|
||||
"SearchQueryPlaceHolderText": "Search query in KQL format",
|
||||
"EmptyFieldErrorMessage": "This field cannot be empty",
|
||||
|
|
|
@ -14,6 +14,8 @@ define([], function() {
|
|||
"ApplyAllFiltersLabel": "Appliquer tous les filters",
|
||||
"RemoveAllFiltersLabel": "Supprimer tous les filtres",
|
||||
"ShowPagingLabel": "Afficher la pagination",
|
||||
"ShowFileIconLabel": "Afficher les icônes de fichier",
|
||||
"ShowCreatedDateLabel": "Afficher la date de création",
|
||||
"NoFilterConfiguredLabel": "Aucun filtre configuré",
|
||||
"SearchQueryPlaceHolderText": "Requête de recherche au format KQL",
|
||||
"EmptyFieldErrorMessage": "Ce champ ne peut pas être vide",
|
||||
|
|
|
@ -13,6 +13,8 @@ declare interface ISearchWebPartStrings {
|
|||
ApplyAllFiltersLabel: string;
|
||||
RemoveAllFiltersLabel: string;
|
||||
ShowPagingLabel: string;
|
||||
ShowFileIconLabel: string;
|
||||
ShowCreatedDateLabel: string;
|
||||
NoFilterConfiguredLabel: string;
|
||||
SearchQueryPlaceHolderText: string;
|
||||
EmptyFieldErrorMessage: string;
|
||||
|
|
|
@ -7,10 +7,19 @@
|
|||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"es6-collections",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue