Improvements (#395)

* Updated @pnp packages to solve an issue with application insights tracking failing the component in IE/Edge.

* Explicit load of the Overlay component to reduce bundle size.

* Store the inital result in order to prevent two calls per page which slows down result loading and is unneeded.
This commit is contained in:
Mikael Svenson 2018-01-20 14:59:21 +01:00 committed by Vesa Juvonen
parent 764d8f10e0
commit 120af41c95
3 changed files with 41 additions and 36 deletions

View File

@ -14,8 +14,8 @@
"@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",
"@pnp/spfx-controls-react": "^1.1.2",
"@pnp/spfx-property-controls": "^1.2.0",
"@types/react": "15.6.6",
"@types/react-addons-shallow-compare": "0.14.17",
"@types/react-addons-test-utils": "0.14.15",

View File

@ -2,7 +2,7 @@ import ISearchDataProvider from "./ISearchDataProvider";
import { ISearchResults, ISearchResult, IRefinementResult, IRefinementValue, IRefinementFilter } from "../models/ISearchResult";
import pnp, { ConsoleListener, Logger, LogLevel, SearchQuery, SearchQueryBuilder, SearchResults, setup, Web, Sort, SortDirection } from "sp-pnp-js";
import { IWebPartContext } from "@microsoft/sp-webpart-base";
import { Text, JsonUtilities, UrlUtilities } from "@microsoft/sp-core-library";
import { Text, JsonUtilities, UrlUtilities } from "@microsoft/sp-core-library";
import sortBy from "lodash-es/sortBy";
import groupBy from 'lodash-es/groupBy';
import mapValues from 'lodash-es/mapValues';
@ -11,6 +11,7 @@ import * as moment from "moment";
class SearchDataProvider implements ISearchDataProvider {
private _initialSearchResult: SearchResults = null;
private _resultsCount: number;
private _context: IWebPartContext;
private _appSearchSettings: SearchQuery;
@ -20,7 +21,7 @@ class SearchDataProvider implements ISearchDataProvider {
public get resultsCount(): number { return this._resultsCount; }
public set resultsCount(value: number) { this._resultsCount = value; }
public set selectedProperties(value: string[]) { this._selectedProperties = value; }
public set selectedProperties(value: string[]) { this._selectedProperties = value; }
public get selectedProperties(): string[] { return this._selectedProperties; }
public set queryTemplate(value: string) { this._queryTemplate = value; }
@ -28,7 +29,7 @@ class SearchDataProvider implements ISearchDataProvider {
public constructor(webPartContext: IWebPartContext) {
this._context = webPartContext;
// Setup the PnP JS instance
const consoleListener = new ConsoleListener();
Logger.subscribe(consoleListener);
@ -52,7 +53,7 @@ class SearchDataProvider implements ISearchDataProvider {
* @return The search results
*/
public async search(query: string, refiners?: string, refinementFilters?: IRefinementFilter[], pageNumber?: number): Promise<ISearchResults> {
let searchQuery: SearchQuery = {};
let sortedRefiners: string[] = [];
@ -88,7 +89,7 @@ class SearchDataProvider implements ISearchDataProvider {
sortedRefiners = refiners.split(",");
searchQuery.Refiners = refiners ? refiners : "";
}
if (refinementFilters) {
if (refinementFilters.length > 0) {
searchQuery.RefinementFilters = [this._buildRefinementQueryString(refinementFilters)];
@ -96,25 +97,29 @@ class SearchDataProvider implements ISearchDataProvider {
}
let results: ISearchResults = {
RelevantResults : [],
RelevantResults: [],
RefinementResults: [],
TotalRows: 0,
};
try {
const r = await pnp.sp.search(searchQuery);
if (!this._initialSearchResult || page == 1) {
this._initialSearchResult = await pnp.sp.search(searchQuery);
}
const allItemsPromises: Promise<any>[] = [];
let refinementResults: IRefinementResult[] = [];
// Need to do this check
// More info here: https://github.com/SharePoint/PnP-JS-Core/issues/337
if (r.RawSearchResults.PrimaryQueryResult) {
if (this._initialSearchResult.RawSearchResults.PrimaryQueryResult) {
// Be careful, there was an issue with paging calculation under 2.0.8 version of sp-pnp-js library
// More info https://github.com/SharePoint/PnP-JS-Core/issues/535
const r2 = await r.getPage(page, this._resultsCount);
let r2 = this._initialSearchResult;
if (page > 1) {
r2 = await this._initialSearchResult.getPage(page, this._resultsCount);
}
const resultRows = r2.RawSearchResults.PrimaryQueryResult.RelevantResults.Table.Rows;
let refinementResultsRows = r2.RawSearchResults.PrimaryQueryResult.RefinementResults;
@ -125,7 +130,7 @@ class SearchDataProvider implements ISearchDataProvider {
resultRows.map((elt) => {
const p1 = new Promise<ISearchResult>((resolvep1, rejectp1) => {
// Build item result dynamically
// We can't type the response here because search results are by definition too heterogeneous so we treat them as key-value object
let result: ISearchResult = {};
@ -137,25 +142,25 @@ class SearchDataProvider implements ISearchDataProvider {
// Get the icon source URL
this._mapToIcon(result.Filename ? result.Filename : Text.format(".{0}", result.FileExtension)).then((iconUrl) => {
result.iconSrc = iconUrl;
result.iconSrc = iconUrl;
resolvep1(result);
}).catch((error) => {
rejectp1(error);
});
});
});
allItemsPromises.push(p1);
allItemsPromises.push(p1);
});
// Map refinement results
refinementRows.map((refiner) => {
let values: IRefinementValue[] = [];
refiner.Entries.map((item) => {
values.push({
RefinementCount: item.RefinementCount,
RefinementName: this._formatDate(item.RefinementName), // This value will appear in the selected filter bar
RefinementName: this._formatDate(item.RefinementName), // This value will appear in the selected filter bar
RefinementToken: item.RefinementToken,
RefinementValue: this._formatDate(item.RefinementValue), // This value will appear in the filter panel
});
@ -169,7 +174,7 @@ class SearchDataProvider implements ISearchDataProvider {
// Resolve all the promises once to get news
const relevantResults: ISearchResult[] = await Promise.all(allItemsPromises);
// Sort refiners according to the property pane value
refinementResults = sortBy(refinementResults, (refinement) => {
@ -178,15 +183,15 @@ class SearchDataProvider implements ISearchDataProvider {
});
results.RelevantResults = relevantResults;
results.RefinementResults = refinementResults,
results.TotalRows = r.TotalRows;
results.RefinementResults = refinementResults;
results.TotalRows = this._initialSearchResult.TotalRows;
}
return results;
} catch (error) {
Logger.write("[SharePointDataProvider.search()]: Error: " + error, LogLevel.Error);
throw error;
}
}
}
/**
@ -194,13 +199,13 @@ class SearchDataProvider implements ISearchDataProvider {
* @param filename The file name (ex: file.pdf)
*/
private async _mapToIcon(filename: string): Promise<string> {
const webAbsoluteUrl = this._context.pageContext.web.absoluteUrl;
const web = new Web(webAbsoluteUrl);
try {
const encodedFileName = filename ? filename.replace(/["']/g, "") : "";
const iconFileName = await web.mapToIcon(encodedFileName,1);
const iconFileName = await web.mapToIcon(encodedFileName, 1);
const iconUrl = webAbsoluteUrl + "/_layouts/15/images/" + iconFileName;
return iconUrl;
@ -228,7 +233,7 @@ class SearchDataProvider implements ISearchDataProvider {
});
}
return updatedInputValue;
return updatedInputValue;
}
/**
@ -236,31 +241,31 @@ class SearchDataProvider implements ISearchDataProvider {
* @param selectedFilters The selected filter array
*/
private _buildRefinementQueryString(selectedFilters: IRefinementFilter[]): string {
let refinementQueryConditions: string[] = [];
let refinementQueryString: string = null;
const refinementFilters = mapValues(groupBy(selectedFilters, 'FilterName'), (values) => {
const refinementFilter = values.map((filter) => {
return filter.Value.RefinementToken;
const refinementFilter = values.map((filter) => {
return filter.Value.RefinementToken;
});
return refinementFilter.length > 1 ? Text.format("or({0})", refinementFilter) : refinementFilter.toString();
});
mapKeys(refinementFilters, (value, key) => {
refinementQueryConditions.push(key + ":" + value);
});
const conditionsCount = refinementQueryConditions.length;
switch (true) {
// No filters
case (conditionsCount === 0): {
refinementQueryString = null;
break;
}
}
// Just one filter
case (conditionsCount === 1): {

View File

@ -10,7 +10,7 @@ import TilesList from "../TilesList/TilesList";
import "../SearchWebPart.scss";
import FilterPanel from "../FilterPanel/FilterPanel";
import Paging from "../Paging/Paging";
import { Overlay } from "office-ui-fabric-react";
import { Overlay } from "office-ui-fabric-react/lib/Overlay";
export default class SearchContainer extends React.Component<ISearchContainerProps, ISearchContainerState> {