From 52b995401f82079c72a8208978a695022b8a9cff Mon Sep 17 00:00:00 2001 From: Franck Cornu Date: Wed, 27 Mar 2019 12:31:49 -0400 Subject: [PATCH 1/2] [ModernSearch] * Revert changes made to new SearchResultsContainer regarding new props handling. --- .../spfx/package-lock.json | 15 ++++++---- .../SearchResultsContainer.tsx | 28 ++++++++++++++----- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/solutions/ModernSearch/react-search-refiners/spfx/package-lock.json b/solutions/ModernSearch/react-search-refiners/spfx/package-lock.json index 00dec554..c5eb9564 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/package-lock.json +++ b/solutions/ModernSearch/react-search-refiners/spfx/package-lock.json @@ -1,6 +1,6 @@ { "name": "pnp-react-search-refiners", - "version": "2.4.0", + "version": "3.0.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -7080,7 +7080,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -7495,7 +7496,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -7551,6 +7553,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7594,12 +7597,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/components/SearchResultsContainer/SearchResultsContainer.tsx b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/components/SearchResultsContainer/SearchResultsContainer.tsx index 73f56f37..07ced796 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/components/SearchResultsContainer/SearchResultsContainer.tsx +++ b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/components/SearchResultsContainer/SearchResultsContainer.tsx @@ -206,12 +206,20 @@ export default class SearchResultsContainer extends React.Component Date: Mon, 6 May 2019 15:33:22 -0400 Subject: [PATCH 2/2] [ModernSearch] - Fixed issue on group expand/collapse defaults https://github.com/SharePoint/sp-dev-solutions/issues/145 --- .../Layouts/LinkPanel/ILinkPanelState.ts | 5 +- .../Layouts/LinkPanel/LinkPanel.tsx | 188 ++++++++++-------- .../Layouts/Vertical/IVerticalState.tsx | 5 +- .../components/Layouts/Vertical/Vertical.tsx | 157 ++++++++------- .../searchResults/SearchResultsWebPart.ts | 4 +- 5 files changed, 200 insertions(+), 159 deletions(-) diff --git a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/ILinkPanelState.ts b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/ILinkPanelState.ts index 09560011..4ac4ea08 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/ILinkPanelState.ts +++ b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/ILinkPanelState.ts @@ -1,9 +1,10 @@ import { IRefinementValue } from "../../../../../models/ISearchResult"; +import { IGroup } from "office-ui-fabric-react/lib/components/GroupedList"; interface ILinkPanelState { showPanel?: boolean; - valueToRemove: IRefinementValue; - expandedGroups?: string[]; + groups?: IGroup[]; + items?: JSX.Element[]; } export default ILinkPanelState; \ No newline at end of file diff --git a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/LinkPanel.tsx b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/LinkPanel.tsx index 47d1cbf4..5fddda1e 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/LinkPanel.tsx +++ b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/LinkPanel/LinkPanel.tsx @@ -7,7 +7,8 @@ import * as update from 'immutabi import { GroupedList, IGroup, - IGroupDividerProps + IGroupDividerProps, + IGroupedList } from 'office-ui-fabric-react/lib/components/GroupedList/index'; import { Scrollbars } from 'react-custom-scrollbars'; import {Link} from 'office-ui-fabric-react/lib/Link'; @@ -15,18 +16,22 @@ import {ActionButton} from 'office-ui-fabric-react/lib/Button'; import styles from './LinkPanel.module.scss'; import * as strings from 'SearchRefinersWebPartStrings'; import TemplateRenderer from '../../Templates/TemplateRenderer'; -import { IRefinementResult } from '../../../../../models/ISearchResult'; +import { IRefinementResult, IRefinementValue } from '../../../../../models/ISearchResult'; import IRefinerConfiguration from '../../../../../models/IRefinerConfiguration'; +import IFilterLayoutProps from '../IFilterLayoutProps'; +import { isEqual } from '@microsoft/sp-lodash-subset'; export default class LinkPanel extends React.Component { + private _groupedList: IGroupedList; + public constructor(props: ILinkPanelProps) { super(props); this.state = { showPanel: false, - expandedGroups: [], - valueToRemove: null + items: [], + groups: [] }; this._onTogglePanel = this._onTogglePanel.bind(this); @@ -39,58 +44,6 @@ export default class LinkPanel extends React.Component { - let items: JSX.Element[] = []; - let groups: IGroup[] = []; - - if (this.props.refinementResults.length === 0) return ; - - // Initialize the Office UI grouped list - this.props.refinementResults.map((refinementResult, i) => { - - // Get group name - let groupName = refinementResult.FilterName; - const configuredFilter = this.props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;}); - groupName = configuredFilter.length > 0 && configuredFilter[0].displayValue ? configuredFilter[0].displayValue : groupName; - - groups.push({ - key: i.toString(), - name: groupName, - count: 1, - startIndex: i, - isDropEnabled: true, - isCollapsed: this.state.expandedGroups.indexOf(groupName) === -1 ? true : false - }); - - // Get selected values for this specfic refiner - // This scenario happens due to the behavior of the Office UI Fabric GroupedList component who recreates child components when a greoup is collapsed/expanded, causing a state reset for sub components - // In this case we use the refiners global state to recreate the 'local' state for this component - const selectedFilter = this.props.selectedFilters.filter(filter => { return filter.FilterName === refinementResult.FilterName;}); - const selectedFilterValues = selectedFilter.length === 1 ? selectedFilter[0].Values : []; - - // Check if the value to remove concerns this refinement result - let valueToRemove = null; - if (this.state.valueToRemove) { - if (refinementResult.Values.filter(value => { - return value.RefinementToken === this.state.valueToRemove.RefinementToken || refinementResult.FilterName === this.state.valueToRemove.RefinementName; }).length > 0 - ) { - valueToRemove = this.state.valueToRemove; - } - } - - items.push( - - ); - }); - const renderSelectedFilterValues: JSX.Element[] = this.props.selectedFilterValues.map((value) => { // Get the 'display name' of the associated refiner for this value @@ -105,9 +58,8 @@ export default class LinkPanel extends React.Component { - this.setState({ - valueToRemove: value - }); + this._initItems(this.props, value); + this._groupedList.forceUpdate(); }}> {filterName} ); @@ -115,7 +67,8 @@ export default class LinkPanel extends React.Component { this._groupedList = g; }} + items={this.state.items} onRenderCell={this._onRenderCell} className={styles.linkPanelLayout__filterPanel__body__group} groupProps={ @@ -123,7 +76,7 @@ export default class LinkPanel extends React.Component; + groups={this.state.groups} />; const renderLinkRemoveAll = this.props.hasSelectedValues ? (
@@ -180,15 +133,22 @@ export default class LinkPanel extends React.Component 0 ? { marginTop: '10px' } : undefined } 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.name] }) : - update(this.state.expandedGroups, { $splice: [[this.state.expandedGroups.indexOf(props.group.name), 1]] }); - - this.setState({ - expandedGroups: updatedExpandedGroups, - }); + props.onToggleCollapse(props.group); }}>
@@ -241,21 +192,86 @@ export default class LinkPanel extends React.Component { + let groups: IGroup[] = []; + props.refinementResults.map((refinementResult, i) => { // Get group name let groupName = refinementResult.FilterName; - const configuredFilter = refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;}); - groupName = configuredFilter.length > 0 && configuredFilter[0].displayValue ? configuredFilter[0].displayValue : groupName; - const showExpanded = configuredFilter.length > 0 && configuredFilter[0].showExpanded ? configuredFilter[0].showExpanded : false; - - if (showExpanded) { - this.setState({ - expandedGroups: update(this.state.expandedGroups, { $push: [groupName] }) - }); + const configuredFilters = props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;}); + groupName = configuredFilters.length > 0 && configuredFilters[0].displayValue ? configuredFilters[0].displayValue : groupName; + let isCollapsed = true; + + const existingGroups = this.state.groups.filter(g => { return g.name === groupName;}); + + if (existingGroups.length > 0 && !shouldResetCollapse) { + isCollapsed = existingGroups[0].isCollapsed; + } else { + isCollapsed = configuredFilters.length > 0 && configuredFilters[0].showExpanded ? !configuredFilters[0].showExpanded : true; } + + let group: IGroup = { + key: i.toString(), + name: groupName, + count: 1, + startIndex: i, + isCollapsed: isCollapsed + }; + + groups.push(group); + }); + + this.setState({ + groups: update(this.state.groups, { $set: groups }) + }); + } + + /** + * Initializes items in for goups in the GroupedList + * @param refinementResults the refinements results + */ + private _initItems(props: IFilterLayoutProps, refinementValueToRemove?: IRefinementValue): void { + + let items: JSX.Element[] = []; + + // Initialize the Office UI grouped list + props.refinementResults.map((refinementResult, i) => { + + const configuredFilter = props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName; }); + + // Get selected values for this specfic refiner + // This scenario happens due to the behavior of the Office UI Fabric GroupedList component who recreates child components when a greoup is collapsed/expanded, causing a state reset for sub components + // In this case we use the refiners global state to recreate the 'local' state for this component + const selectedFilter = props.selectedFilters.filter(filter => { return filter.FilterName === refinementResult.FilterName; }); + const selectedFilterValues = selectedFilter.length === 1 ? selectedFilter[0].Values : []; + + // Check if the value to remove concerns this refinement result + let valueToRemove = null; + if (refinementValueToRemove) { + if (refinementResult.Values.filter(value => { + return value.RefinementToken ===refinementValueToRemove.RefinementToken || refinementResult.FilterName === refinementValueToRemove.RefinementName; }).length > 0 + ) { + valueToRemove = refinementValueToRemove; + } + } + + items.push( + + ); + }); + + this.setState({ + items: update(this.state.items, { $set: items }) }); } } \ No newline at end of file diff --git a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/IVerticalState.tsx b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/IVerticalState.tsx index 973985eb..9a408aef 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/IVerticalState.tsx +++ b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/IVerticalState.tsx @@ -1,5 +1,8 @@ +import { IGroup } from "office-ui-fabric-react/lib/components/GroupedList"; + interface IVerticalState { - expandedGroups?: string[]; + groups?: IGroup[]; + items?: JSX.Element[]; } export default IVerticalState; \ No newline at end of file diff --git a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/Vertical.tsx b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/Vertical.tsx index def79cd6..6fec46a9 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/Vertical.tsx +++ b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchRefiners/components/Layouts/Vertical/Vertical.tsx @@ -5,22 +5,25 @@ import * as update from 'immutability-helper'; import { GroupedList, IGroup, - IGroupDividerProps + IGroupDividerProps, + IGroupedList } from 'office-ui-fabric-react/lib/components/GroupedList/index'; import {Link} from 'office-ui-fabric-react/lib/Link'; import styles from './Vertical.module.scss'; import * as strings from 'SearchRefinersWebPartStrings'; import TemplateRenderer from '../../Templates/TemplateRenderer'; -import { IRefinementResult } from '../../../../../models/ISearchResult'; -import IRefinerConfiguration from '../../../../../models/IRefinerConfiguration'; +import { isEqual } from '@microsoft/sp-lodash-subset'; export default class Vertical extends React.Component { + private _groupedList: IGroupedList; + public constructor(props: IFilterLayoutProps) { super(props); this.state = { - expandedGroups: [] + items: [], + groups: [] }; this._removeAllFilters = this._removeAllFilters.bind(this); @@ -30,49 +33,12 @@ export default class Vertical extends React.Component { - let items: JSX.Element[] = []; - let groups: IGroup[] = []; let noResultsElement: JSX.Element; - // Initialize the Office UI grouped list - this.props.refinementResults.map((refinementResult, i) => { - - // Get group name - let groupName = refinementResult.FilterName; - const configuredFilter = this.props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName; }); - groupName = configuredFilter.length > 0 && configuredFilter[0].displayValue ? configuredFilter[0].displayValue : groupName; - - groups.push({ - key: i.toString(), - name: groupName, - count: 1, - startIndex: i, - isDropEnabled: true, - isCollapsed: this.state.expandedGroups.indexOf(groupName) === -1 ? true : false - }); - - // Get selected values for this specfic refiner - // This scenario happens due to the behavior of the Office UI Fabric GroupedList component who recreates child components when a greoup is collapsed/expanded, causing a state reset for sub components - // In this case we use the refiners global state to recreate the 'local' state for this component - const selectedFilter = this.props.selectedFilters.filter(filter => { return filter.FilterName === refinementResult.FilterName; }); - const selectedFilterValues = selectedFilter.length === 1 ? selectedFilter[0].Values : []; - - items.push( - - ); - }); - const renderAvailableFilters = (this.props.refinementResults.length > 0) ? { this._groupedList = g; }} onRenderCell={this._onRenderCell} className={styles.verticalLayout__filterPanel__body__group} groupProps={ @@ -80,7 +46,7 @@ export default class Vertical extends React.Component : noResultsElement; + groups={this.state.groups} /> : noResultsElement; const renderLinkRemoveAll = this.props.hasSelectedValues ? (
@@ -98,11 +64,23 @@ export default class Vertical extends React.Component 0 ? { marginTop: '10px' } : undefined} 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.name] }) : - update(this.state.expandedGroups, { $splice: [[this.state.expandedGroups.indexOf(props.group.name), 1]] }); - - this.setState({ - expandedGroups: updatedExpandedGroups, - }); - props.onToggleCollapse(props.group); }}>
@@ -149,21 +116,75 @@ export default class Vertical extends React.Component { + let groups: IGroup[] = []; + props.refinementResults.map((refinementResult, i) => { // Get group name let groupName = refinementResult.FilterName; - const configuredFilter = refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;}); - groupName = configuredFilter.length > 0 && configuredFilter[0].displayValue ? configuredFilter[0].displayValue : groupName; - const showExpanded = configuredFilter.length > 0 && configuredFilter[0].showExpanded ? configuredFilter[0].showExpanded : false; - - if (showExpanded) { - this.setState({ - expandedGroups: update(this.state.expandedGroups, { $push: [groupName] }) - }); + const configuredFilters = props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName;}); + groupName = configuredFilters.length > 0 && configuredFilters[0].displayValue ? configuredFilters[0].displayValue : groupName; + let isCollapsed = true; + + const existingGroups = this.state.groups.filter(g => { return g.name === groupName;}); + + if (existingGroups.length > 0 && !shouldResetCollapse) { + isCollapsed = existingGroups[0].isCollapsed; + } else { + isCollapsed = configuredFilters.length > 0 && configuredFilters[0].showExpanded ? !configuredFilters[0].showExpanded : true; } + + let group: IGroup = { + key: i.toString(), + name: groupName, + count: 1, + startIndex: i, + isCollapsed: isCollapsed + }; + + groups.push(group); + }); + + this.setState({ + groups: update(this.state.groups, { $set: groups }) + }); + } + + /** + * Initializes items in for goups in the GroupedList + * @param refinementResults the refinements results + */ + private _initItems(props: IFilterLayoutProps): void { + + let items: JSX.Element[] = []; + + // Initialize the Office UI grouped list + props.refinementResults.map((refinementResult, i) => { + + const configuredFilter = props.refinersConfiguration.filter(e => { return e.refinerName === refinementResult.FilterName; }); + + // Get selected values for this specfic refiner + // This scenario happens due to the behavior of the Office UI Fabric GroupedList component who recreates child components when a greoup is collapsed/expanded, causing a state reset for sub components + // In this case we use the refiners global state to recreate the 'local' state for this component + const selectedFilter = props.selectedFilters.filter(filter => { return filter.FilterName === refinementResult.FilterName; }); + const selectedFilterValues = selectedFilter.length === 1 ? selectedFilter[0].Values : []; + + items.push( + + ); + }); + + this.setState({ + items: update(this.state.items, { $set: items }) }); } } \ No newline at end of file diff --git a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/SearchResultsWebPart.ts b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/SearchResultsWebPart.ts index f6d3f6d3..b9604acd 100644 --- a/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/SearchResultsWebPart.ts +++ b/solutions/ModernSearch/react-search-refiners/spfx/src/webparts/searchResults/SearchResultsWebPart.ts @@ -27,7 +27,7 @@ import ISearchService from '../../services/SearchService/ISearchService'; import ITaxonomyService from '../../services/TaxonomyService/ITaxonomyService'; import ResultsLayoutOption from '../../models/ResultsLayoutOption'; import TemplateService from '../../services/TemplateService/TemplateService'; -import { isEmpty, find } from '@microsoft/sp-lodash-subset'; +import { isEmpty, find, sortBy } from '@microsoft/sp-lodash-subset'; import MockSearchService from '../../services/SearchService/MockSearchService'; import MockTemplateService from '../../services/TemplateService/MockTemplateService'; import SearchService from '../../services/SearchService/SearchService'; @@ -128,7 +128,7 @@ export default class SearchResultsWebPart extends BaseClientSideWebPart