Skip to content

Commit ee44a66

Browse files
committed
Fix of #1026: providing trimDuplicates and additionalQuery properties to site picker control
1 parent f957409 commit ee44a66

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

docs/documentation/docs/controls/SitePicker.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ The `SitePicker` control can be configured with the following properties:
5252
| isDesc | boolean | no | Specifies if the list is sorted in descending order. Default: `false`. |
5353
| label | string | no | Label to use for the control. |
5454
| limitToCurrentSiteCollection | boolean | no | Specifies if the options should be limited by the current site collections. Taken into consideration if selectionMode is set to `web`. |
55-
| mode | `'site' \| 'web' \| 'hub'` | no | Defines what entities are available for selection: site collections, sites, hub sites. Default: `web`. |
55+
| mode | `'site' | 'web' | 'hub'` | no | Defines what entities are available for selection: site collections, sites, hub sites. Default: `web`. |
5656
| multiSelect | boolean | no | Optional mode indicates if multi-choice selections is allowed. Default: `true`. |
5757
| onChange | `(selectedSites: ISite[]) => void` | yes | Selection change handler. |
58-
| orderBy | `'title' \| 'url'` | no | Specifices if the list is sorted by title or url. Default: `title`. |
58+
| orderBy | `'title' | 'url'` | no | Specifices if the list is sorted by title or url. Default: `title`. |
5959
| placeholder | string | no | Placeholder label to show in the dropdown. |
6060
| searchPlaceholder | string | no | Search input placeholder text. Displayed until search text is entered. |
61+
| trimDuplicates | boolean | no | Specifies if the duplicates should be trimmed. false by default. Applicable if mode is set to site or web. |
62+
| additionalQuery | string | no | If provided will be added to the search query as AND part. Applicable if mode is set to site or web. |
6163

6264
Interface `ISite`
6365

src/controls/sitePicker/ISitePicker.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,16 @@ export interface ISitePickerProps {
100100
* If provided, additional class name to provide on the dropdown element.
101101
*/
102102
className?: string;
103+
104+
/**
105+
* Specifies if the duplicates should be trimmed. false by default.
106+
* Applicable if mode is set to site or web.
107+
*/
108+
trimDuplicates?: boolean;
109+
110+
/**
111+
* If provided will be added to the search query as AND part.
112+
* Applicable if mode is set to site or web.
113+
*/
114+
additionalQuery?: string;
103115
}

src/controls/sitePicker/SitePicker.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
7171
searchPlaceholder,
7272
deferredSearchTime,
7373
className,
74-
selectedSites
74+
selectedSites,
75+
trimDuplicates,
76+
additionalQuery
7577
} = props;
7678

7779
const [isLoading, setIsLoading] = React.useState<boolean>();
@@ -235,7 +237,7 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
235237
promise = getHubSites(context);
236238
}
237239
else {
238-
promise = getAllSites(context, mode !== 'site', limitToCurrentSiteCollection);
240+
promise = getAllSites(context, mode !== 'site', limitToCurrentSiteCollection, trimDuplicates === true, additionalQuery);
239241
}
240242

241243
promise.then(newSites => {

src/services/SPSitesService.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,36 @@ import { BaseComponentContext } from '@microsoft/sp-component-base';
22
import { ISite } from '../controls/sitePicker/ISitePicker';
33
import { SPHttpClient } from '@microsoft/sp-http';
44

5-
const getAllSitesInternal = async (ctx: BaseComponentContext, queryText: string): Promise<ISite[]> => {
5+
const getAllSitesInternal = async (ctx: BaseComponentContext, queryText: string, trimDuplicates: boolean): Promise<ISite[]> => {
66
let startRow = 0;
77
let rowLimit = 500;
88
let totalRows = 0;
99
const values: any[] = [];
1010

11+
const searchRequest = {
12+
QueryTemplate: queryText,
13+
RowLimit: rowLimit,
14+
TrimDuplicates: trimDuplicates,
15+
SelectProperties: ['SiteId', 'SiteID', 'WebId', 'DepartmentId', 'Title', 'Path'],
16+
StartRow: 0
17+
};
18+
19+
const requestUrl = `${ctx.pageContext.web.absoluteUrl}/_api/search/postquery`;
20+
1121
//
1222
// getting all sites
1323
//
1424
do {
15-
let userRequestUrl: string = `${ctx.pageContext.web.absoluteUrl}/_api/search/query?querytext='${queryText}'&selectproperties='SiteId,SiteID,WebId,DepartmentId,Title,Path'&rowlimit=${rowLimit}&startrow=${startRow}`;
16-
let searchResponse = await ctx.spHttpClient.get(userRequestUrl, SPHttpClient.configurations.v1);
25+
searchRequest.StartRow = startRow;
26+
27+
let searchResponse = await ctx.spHttpClient.post(requestUrl, SPHttpClient.configurations.v1, {
28+
body: JSON.stringify({ request: searchRequest }),
29+
headers: {
30+
'Accept': 'application/json;odata=nometadata',
31+
'Content-Type': 'application/json;charset=utf-8',
32+
'odata-version': '3.0'
33+
}
34+
});
1735
let sitesResponse = await searchResponse.json();
1836
let relevantResults = sitesResponse.PrimaryQueryResult.RelevantResults;
1937

@@ -61,16 +79,19 @@ const getAllSitesInternal = async (ctx: BaseComponentContext, queryText: string)
6179
return res;
6280
};
6381

64-
export const getAllSites = async (ctx: BaseComponentContext, includeWebs: boolean, currentSiteCollectionOnly: boolean): Promise<ISite[]> => {
82+
export const getAllSites = async (ctx: BaseComponentContext, includeWebs: boolean, currentSiteCollectionOnly: boolean, trimDuplicates: boolean, additionaQuery?: string | undefined): Promise<ISite[]> => {
6583

6684
let rootUrl: string = ctx.pageContext.web.absoluteUrl;
6785
if (ctx.pageContext.web.serverRelativeUrl !== '/' && (!includeWebs || !currentSiteCollectionOnly)) {
6886
rootUrl = ctx.pageContext.web.absoluteUrl.replace(ctx.pageContext.web.serverRelativeUrl, '');
6987
}
7088

71-
const queryText = `contentclass:STS_Site${includeWebs ? ' contentclass:STS_Web' : ''} Path:${rootUrl}*`;
89+
let queryText = `(contentclass:STS_Site${includeWebs ? ' contentclass:STS_Web' : ''} Path:${rootUrl}*)`;
90+
if (additionaQuery) {
91+
queryText += ` AND (${additionaQuery})`;
92+
}
7293

73-
return getAllSitesInternal(ctx, queryText);
94+
return getAllSitesInternal(ctx, queryText, trimDuplicates);
7495
};
7596

7697
export const getHubSites = async (ctx: BaseComponentContext): Promise<ISite[]> => {

0 commit comments

Comments
 (0)