diff --git a/samples/react-content-query-webpart/Misc/allsites_v2.gif b/samples/react-content-query-webpart/Misc/allsites_v2.gif new file mode 100644 index 000000000..23286bbb1 Binary files /dev/null and b/samples/react-content-query-webpart/Misc/allsites_v2.gif differ diff --git a/samples/react-content-query-webpart/README.md b/samples/react-content-query-webpart/README.md index d7ce004dc..3863dacdb 100644 --- a/samples/react-content-query-webpart/README.md +++ b/samples/react-content-query-webpart/README.md @@ -28,6 +28,7 @@ Version|Date|Comments 1.0.1|July 23rd 15, 2017|Updated to GA Version 1.0.3|August 12, 2017|Added external scripts functionnality 1.0.4|August 31, 2017|Fixed a bug where tenant sites/subsites were missing from the **Web Url** dropdown +1.0.5|September 1st, 2017|Added a **Site Url** parameter next to the **Web Url** parameter in order to narrow down the results ## 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.** @@ -38,7 +39,7 @@ Version|Date|Comments The WebPart uses the search in order to get all sites under the current domain, which makes it possible to query not only subsites but other site collections and their subsites as well. - +
### Unlimited filters diff --git a/samples/react-content-query-webpart/config/package-solution.json b/samples/react-content-query-webpart/config/package-solution.json index f9e0d2b57..41683ca79 100644 --- a/samples/react-content-query-webpart/config/package-solution.json +++ b/samples/react-content-query-webpart/config/package-solution.json @@ -2,7 +2,7 @@ "solution": { "name": "React Content Query", "id": "00406271-0276-406f-9666-512623eb6709", - "version": "1.0.4.0" + "version": "1.0.5.0" }, "paths": { "zippedPackage": "solution/react-content-query-webpart.sppkg" diff --git a/samples/react-content-query-webpart/config/write-manifests.json b/samples/react-content-query-webpart/config/write-manifests.json index 14a873efe..1c5a397c1 100644 --- a/samples/react-content-query-webpart/config/write-manifests.json +++ b/samples/react-content-query-webpart/config/write-manifests.json @@ -1,3 +1,3 @@ { - "cdnBasePath": "https://publiccdn.sharepointonline.com/spptechnologies.sharepoint.com/110700492eeea162ee5bad0f35b1f0061ded8bf436ce0199efe2a4d24109e1c0df1ec594/react-content-query-1.0.4" + "cdnBasePath": "https://publiccdn.sharepointonline.com/spptechnologies.sharepoint.com/110700492eeea162ee5bad0f35b1f0061ded8bf436ce0199efe2a4d24109e1c0df1ec594/react-content-query-1.0.5" } \ No newline at end of file diff --git a/samples/react-content-query-webpart/package-lock.json b/samples/react-content-query-webpart/package-lock.json index 129b67da5..5154c3713 100644 --- a/samples/react-content-query-webpart/package-lock.json +++ b/samples/react-content-query-webpart/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-content-query", - "version": "1.0.2", + "version": "1.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/samples/react-content-query-webpart/package.json b/samples/react-content-query-webpart/package.json index 87452ad84..b0461d2c4 100644 --- a/samples/react-content-query-webpart/package.json +++ b/samples/react-content-query-webpart/package.json @@ -1,6 +1,6 @@ { "name": "react-content-query", - "version": "1.0.4", + "version": "1.0.5", "private": true, "engines": { "node": ">=0.10.0" diff --git a/samples/react-content-query-webpart/sharepoint/solution/react-content-query-webpart.sppkg b/samples/react-content-query-webpart/sharepoint/solution/react-content-query-webpart.sppkg index 2fab5c7ce..f682300b4 100644 Binary files a/samples/react-content-query-webpart/sharepoint/solution/react-content-query-webpart.sppkg and b/samples/react-content-query-webpart/sharepoint/solution/react-content-query-webpart.sppkg differ diff --git a/samples/react-content-query-webpart/src/common/constants/ContentQueryConstants.ts b/samples/react-content-query-webpart/src/common/constants/ContentQueryConstants.ts index 6b9722566..e19689076 100644 --- a/samples/react-content-query-webpart/src/common/constants/ContentQueryConstants.ts +++ b/samples/react-content-query-webpart/src/common/constants/ContentQueryConstants.ts @@ -4,6 +4,7 @@ export class ContentQueryConstants { /************************************************************** * WebPart Properties **************************************************************/ + public static readonly propertySiteUrl = "siteUrl"; public static readonly propertyWebUrl = "webUrl"; public static readonly propertyListTitle = "listTitle"; public static readonly propertyOrderBy = "orderBy"; diff --git a/samples/react-content-query-webpart/src/common/services/ContentQueryService.ts b/samples/react-content-query-webpart/src/common/services/ContentQueryService.ts index c5763e9dc..47fbc90c1 100644 --- a/samples/react-content-query-webpart/src/common/services/ContentQueryService.ts +++ b/samples/react-content-query-webpart/src/common/services/ContentQueryService.ts @@ -40,6 +40,7 @@ export class ContentQueryService implements IContentQueryService { /*************************************************************************** * Stores the first async calls locally to avoid useless redundant calls ***************************************************************************/ + private siteUrlOptions: IDropdownOption[]; private webUrlOptions: IDropdownOption[]; private listTitleOptions: IDropdownOption[]; private orderByOptions: IDropdownOption[]; @@ -143,13 +144,53 @@ export class ContentQueryService implements IContentQueryService { }); } - + /************************************************************************************************** * Gets the available webs for the current user **************************************************************************************************/ - public getWebUrlOptions(): Promise { + public getSiteUrlOptions(): Promise { + Log.verbose(this.logSource, "Loading dropdown options for toolpart property 'Site Url'...", this.context.serviceScope); + + // Resolves the already loaded data if available + if(this.siteUrlOptions) { + return Promise.resolve(this.siteUrlOptions); + } + + // Otherwise, performs a REST call to get the data + return new Promise((resolve,reject) => { + let serverUrl = Text.format("{0}//{1}", window.location.protocol, window.location.hostname); + + this.searchService.getSitesStartingWith(serverUrl) + .then((urls) => { + let options:IDropdownOption[] = [ { key: "", text: strings.SiteUrlFieldPlaceholder } ]; + let urlOptions:IDropdownOption[] = urls.sort().map((url) => { + let serverRelativeUrl = !isEmpty(url.replace(serverUrl, '')) ? url.replace(serverUrl, '') : '/'; + return { key: url, text: serverRelativeUrl }; + }); + options = options.concat(urlOptions); + this.siteUrlOptions = options; + resolve(options); + }) + .catch((error) => { + reject(error); + } + ); + }); + } + + + /************************************************************************************************** + * Gets the available webs for the current user + * @param siteUrl : The url of the site from which webs must be loaded from + **************************************************************************************************/ + public getWebUrlOptions(siteUrl: string): Promise { Log.verbose(this.logSource, "Loading dropdown options for toolpart property 'Web Url'...", this.context.serviceScope); + // Resolves an empty array if site is null + if (isEmpty(siteUrl)) { + return Promise.resolve(new Array()); + } + // Resolves the already loaded data if available if(this.webUrlOptions) { return Promise.resolve(this.webUrlOptions); @@ -157,14 +198,13 @@ export class ContentQueryService implements IContentQueryService { // Otherwise, performs a REST call to get the data return new Promise((resolve,reject) => { - let serverUrl = Text.format("{0}//{1}", window.location.protocol, window.location.hostname); - this.searchService.getWebUrlsForDomain(serverUrl) - .then((urls:string[]) => { + this.searchService.getWebsFromSite(siteUrl) + .then((urls) => { let options:IDropdownOption[] = [ { key: "", text: strings.WebUrlFieldPlaceholder } ]; let urlOptions:IDropdownOption[] = urls.sort().map((url) => { - let serverRelativeUrl = !isEmpty(url.replace(serverUrl, '')) ? url.replace(serverUrl, '') : '/'; - return { key: url, text: serverRelativeUrl }; + let siteRelativeUrl = !isEmpty(url.replace(siteUrl, '')) ? url.replace(siteUrl, '') : '/'; + return { key: url, text: siteRelativeUrl }; }); options = options.concat(urlOptions); this.webUrlOptions = options; @@ -448,6 +488,15 @@ export class ContentQueryService implements IContentQueryService { } + /*************************************************************************** + * Resets the stored 'list title' options + ***************************************************************************/ + public clearCachedWebUrlOptions() { + Log.verbose(this.logSource, "Clearing cached dropdown options for toolpart property 'Web Url'...", this.context.serviceScope); + this.webUrlOptions = null; + } + + /*************************************************************************** * Resets the stored 'list title' options ***************************************************************************/ diff --git a/samples/react-content-query-webpart/src/common/services/IContentQueryService.ts b/samples/react-content-query-webpart/src/common/services/IContentQueryService.ts index f8703790a..0e24f6234 100644 --- a/samples/react-content-query-webpart/src/common/services/IContentQueryService.ts +++ b/samples/react-content-query-webpart/src/common/services/IContentQueryService.ts @@ -8,7 +8,8 @@ import { IQuerySettings } from '../../webparts/contentQuer export interface IContentQueryService { getTemplateContext: (querySettings: IQuerySettings, callTimeStamp: number) => Promise; getFileContent: (fileUrl: string) => Promise; - getWebUrlOptions: () => Promise; + getSiteUrlOptions: () => Promise; + getWebUrlOptions: (siteUrl: string) => Promise; getListTitleOptions: (webUrl: string) => Promise; getOrderByOptions: (webUrl: string, listTitle: string) => Promise; getFilterFields: (webUrl: string, listTitle: string) => Promise; @@ -18,6 +19,7 @@ export interface IContentQueryService { ensureFileResolves: (filePath: string) => Promise<{}>; isValidTemplateFile: (filePath: string) => boolean; generateDefaultTemplate: (viewFields: string[]) => string; + clearCachedWebUrlOptions: () => void; clearCachedListTitleOptions: () => void; clearCachedOrderByOptions: () => void; clearCachedFilterFields: () => void; diff --git a/samples/react-content-query-webpart/src/common/services/ListService.ts b/samples/react-content-query-webpart/src/common/services/ListService.ts index b1b7705d6..f695079bd 100644 --- a/samples/react-content-query-webpart/src/common/services/ListService.ts +++ b/samples/react-content-query-webpart/src/common/services/ListService.ts @@ -79,7 +79,8 @@ export class ListService { * Returns a sorted array of all available list titles for the specified web * @param webUrl : The web URL from which the specified list is located * @param listTitle : The title of the list from which to load the fields - * @param selectProperties : Optionnaly, the select properties to narrow down the query scope + * @param selectProperties : Optionnaly, the select properties to narrow down the query size + * @param orderBy : Optionnaly, the by which the results needs to be ordered **************************************************************************************************/ public getListFields(webUrl: string, listTitle: string, selectProperties?: string[], orderBy?: string): Promise { return new Promise((resolve,reject) => { diff --git a/samples/react-content-query-webpart/src/common/services/SearchService.ts b/samples/react-content-query-webpart/src/common/services/SearchService.ts index bc0b022ec..22bfb02ff 100644 --- a/samples/react-content-query-webpart/src/common/services/SearchService.ts +++ b/samples/react-content-query-webpart/src/common/services/SearchService.ts @@ -19,43 +19,156 @@ export class SearchService { /************************************************************************************************** - * Returns the web urls starting with the specified domain to which the current user has access - * @param domainUrl : The url of the web which contains the specified list + * Recursively executes the specified search query until all results are fetched + * @param webUrl : The web url from which to call the REST API + * @param queryParameters : The search query parameters following the "/_api/search/query?" part **************************************************************************************************/ - public getWebUrlsForDomain(domainUrl: string): Promise { - return new Promise((resolve,reject) => { - let endpoint = Text.format("{0}/_api/search/query?querytext='Path:{0}/* AND (contentclass:STS_Site OR contentclass:STS_Web)'&selectproperties='Path'&trimduplicates=false&rowLimit=500", domainUrl); + public getSearchResultsRecursive(webUrl: string, queryParameters: string): Promise { + return new Promise((resolve,reject) => { + + // Executes the search request for a first time in order to have an idea of the returned rows vs total results + this.getSearchResults(webUrl, queryParameters) + .then((results: any) => { + + // If there is more rows available... + let relevantResults = results.PrimaryQueryResult.RelevantResults; + let initialResults:any[] = relevantResults.Table.Rows; + + if(relevantResults.TotalRowsIncludingDuplicates > relevantResults.RowCount) { + + // Stores and executes all the missing calls in parallel until we have ALL results + let promises = new Array>(); + let nbPromises = Math.ceil(relevantResults.TotalRowsIncludingDuplicates / relevantResults.RowCount); + + for(let i = 1; i < nbPromises; i++) { + let nextStartRow = (i * relevantResults.RowCount); + promises.push(this.getSearchResults(webUrl, queryParameters, nextStartRow)); + } + + // Once the missing calls are done, concatenates their results to the first request + Promise.all(promises).then((values) => { + for(let recursiveResults of values) { + initialResults = initialResults.concat(recursiveResults.PrimaryQueryResult.RelevantResults.Table.Rows); + } + results.PrimaryQueryResult.RelevantResults.Table.Rows = initialResults; + results.PrimaryQueryResult.RelevantResults.RowCount = initialResults.length; + resolve(results); + }); + + } + // If no more rows are available + else { + resolve(results); + } + }) + .catch((error) => { + reject(error); + } + ); + }); + } + + /************************************************************************************************** + * Recursively executes the specified search query using batches of 500 results until all results are fetched + * @param webUrl : The web url from which to call the search API + * @param queryParameters : The search query parameters following the "/_api/search/query?" part + * @param startRow : The row from which the search needs to return the results from + **************************************************************************************************/ + public getSearchResults(webUrl: string, queryParameters: string, startRow?: number): Promise { + return new Promise((resolve,reject) => { + + queryParameters = this.ensureSearchQueryParameter(queryParameters, 'StartRow', startRow); + let endpoint = Text.format("{0}/_api/search/query?{1}", webUrl, queryParameters); - // Gets the available webs for the current domain with a search query this.spHttpClient.get(endpoint, SPHttpClient.configurations.v1).then((response: SPHttpClientResponse) => { if(response.ok) { - response.json().then((data:any) => { - try { - let urls:string[] = []; - let pathIndex = null; - - for(let result of data.PrimaryQueryResult.RelevantResults.Table.Rows) { - // Stores the index of the "Path" cell on the first loop in order to avoid finding the cell on every loop - if(!pathIndex) { - let pathCell = result.Cells.filter((cell) => { return cell.Key == "Path"; })[0]; - pathIndex = result.Cells.indexOf(pathCell); - } - urls.push(result.Cells[pathIndex].Value); - } - resolve(urls); - } - catch(error) { - reject(error); - } - }) - .catch((error) => { reject(error); }); + resolve(response.json()); } else { reject(response.statusText); } }) .catch((error) => { reject(error); }); - }); + }); + } + + + /************************************************************************************************** + * Recursively searches for all site collections with a path which starts by the specified url + * @param startingUrl : The url of the domain from which to find the site collections + **************************************************************************************************/ + public getSitesStartingWith(startingUrl: string): Promise { + return new Promise((resolve,reject) => { + let queryProperties = Text.format("querytext='Path:{0}/* AND contentclass:STS_Site'&selectproperties='Path'&trimduplicates=false&rowLimit=500", startingUrl); + + this.getSearchResultsRecursive(startingUrl, queryProperties) + .then((results: any) => { + resolve(this.getPathsFromResults(results)); + }) + .catch((error) => { + reject(error); + } + ); + }); + } + + + /************************************************************************************************** + * Recursively searches for all site collections with a path which starts by the specified url + * @param siteUrl : The url of the site collection from which to find the webs + **************************************************************************************************/ + public getWebsFromSite(siteUrl: string): Promise { + return new Promise((resolve,reject) => { + let queryProperties = Text.format("querytext='SiteName:{0} AND (contentclass:STS_Site OR contentclass:STS_Web)'&selectproperties='Path'&trimduplicates=false&rowLimit=500&filter=", siteUrl); + + this.getSearchResultsRecursive(siteUrl, queryProperties) + .then((results: any) => { + resolve(this.getPathsFromResults(results)); + }) + .catch((error) => { + reject(error); + } + ); + }); + } + + + /************************************************************************************************** + * Recursively executes the specified search query using batches of 500 results until all results are fetched + * @param queryParameters : The search query parameters following the "/_api/search/query?" part + * @param parameterName : The name of the parameter that needs to be ensured + * @param parameterValue : The value of the parameter that needs to be ensured + **************************************************************************************************/ + private ensureSearchQueryParameter(queryParameters: string, parameterName: string, parameterValue: any): string { + if(parameterValue) { + let strParameter = Text.format("{0}={1}", parameterName, parameterValue); + queryParameters = queryParameters.replace(new RegExp('StartRow=\\d*', 'gi'), strParameter); + + if(queryParameters.toLowerCase().indexOf(parameterName) < 0) { + queryParameters += ('&' + strParameter); + } + } + return queryParameters; + } + + + /************************************************************************************************** + * Gets the paths out of the specified search results + * @param results : The url of the domain from which to find the site collections + **************************************************************************************************/ + private getPathsFromResults(results: any): string[] { + let urls:string[] = []; + let pathIndex = null; + + for(let result of results.PrimaryQueryResult.RelevantResults.Table.Rows) { + // Stores the index of the "Path" cell on the first loop in order to avoid finding the cell on every loop + if(!pathIndex) { + let pathCell = result.Cells.filter((cell) => { return cell.Key == "Path"; })[0]; + pathIndex = result.Cells.indexOf(pathCell); + } + urls.push(result.Cells[pathIndex].Value); + } + return urls; } } \ No newline at end of file diff --git a/samples/react-content-query-webpart/src/common/services/TaxonomyService.ts b/samples/react-content-query-webpart/src/common/services/TaxonomyService.ts index 55deb9c46..f1d1d62bc 100644 --- a/samples/react-content-query-webpart/src/common/services/TaxonomyService.ts +++ b/samples/react-content-query-webpart/src/common/services/TaxonomyService.ts @@ -1,6 +1,5 @@ import { Text } from '@microsoft/sp-core-library'; import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http'; -import { SPComponentLoader } from '@microsoft/sp-loader'; import { isEmpty } from '@microsoft/sp-lodash-subset'; export class TaxonomyService { @@ -84,39 +83,4 @@ export class TaxonomyService { }); } - - /************************************************************************************* - * Ensures SP.js and its dependencies in order to be able to do JSOM later on - *************************************************************************************/ - private ensureJSOMDependencies(): Promise<{}> { - if(window['SP']) { - return Promise.resolve(); - } - else { - return SPComponentLoader.loadScript('/_layouts/15/init.js', { - globalExportsName: '$_global_init' - }) - .then((): Promise<{}> => { - return SPComponentLoader.loadScript('/_layouts/15/MicrosoftAjax.js', { - globalExportsName: 'Sys' - }); - }) - .then((): Promise<{}> => { - return SPComponentLoader.loadScript('/_layouts/15/SP.Runtime.js', { - globalExportsName: 'SP' - }); - }) - .then((): Promise<{}> => { - return SPComponentLoader.loadScript('/_layouts/15/SP.js', { - globalExportsName: 'SP' - }); - }) - .then((): Promise<{}> => { - return SPComponentLoader.loadScript('/_layouts/15/SP.Taxonomy.js', { - globalExportsName: 'SP.Taxonomy' - }); - }); - } - } - } \ No newline at end of file diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.manifest.json b/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.manifest.json index b1e248da9..2ce441fed 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.manifest.json +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.manifest.json @@ -4,7 +4,7 @@ "id": "46edf08f-95c7-4ca7-9146-6471f9f471be", "alias": "ContentQueryWebPart", "componentType": "WebPart", - "version": "1.0.4", + "version": "1.0.5", "manifestVersion": 2, "preconfiguredEntries": [{ diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.ts b/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.ts index 6bca6aefe..0d2f9c33f 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.ts +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/ContentQueryWebPart.ts @@ -38,6 +38,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart { + return this.ContentQueryService.getSiteUrlOptions(); + } + + /*************************************************************************** * Loads the dropdown options for the webUrl property ***************************************************************************/ private loadWebUrlOptions(): Promise { - return this.ContentQueryService.getWebUrlOptions(); + return this.ContentQueryService.getWebUrlOptions(this.properties.siteUrl); } @@ -394,7 +417,14 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart { return this.properties.webUrl; }); + this.webUrlDropdown.properties.selectedKey = ""; + this.webUrlDropdown.properties.disabled = isEmpty(this.properties.siteUrl); + this.webUrlDropdown.render(); + } + + /*************************************************************************** * Resets the List Title property pane and re-renders it ***************************************************************************/ diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/IContentQueryWebPartProps.ts b/samples/react-content-query-webpart/src/webparts/contentQuery/IContentQueryWebPartProps.ts index 3293954d9..211b0d792 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/IContentQueryWebPartProps.ts +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/IContentQueryWebPartProps.ts @@ -1,6 +1,7 @@ import { IQueryFilter } from "../../controls/PropertyPaneQueryFilterPanel/components/QueryFilter/IQueryFilter"; export interface IContentQueryWebPartProps { + siteUrl: string; webUrl: string; listTitle: string; limitEnabled: boolean; diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/components/ContentQuery.tsx b/samples/react-content-query-webpart/src/webparts/contentQuery/components/ContentQuery.tsx index cf397d3ca..aaa4ab08c 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/components/ContentQuery.tsx +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/components/ContentQuery.tsx @@ -232,7 +232,8 @@ export default class ContentQuery extends React.Component { this.props.strings.mandatoryProperties } + diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/components/IContentQueryProps.ts b/samples/react-content-query-webpart/src/webparts/contentQuery/components/IContentQueryProps.ts index 13ca6851e..b6d4becef 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/components/IContentQueryProps.ts +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/components/IContentQueryProps.ts @@ -6,6 +6,7 @@ import { IQuerySettings } from './IQuerySettings'; export interface IContentQueryProps { onLoadTemplate: (templateUrl: string) => Promise; onLoadTemplateContext: (querySettings: IQuerySettings, callTimeStamp: number) => Promise; + siteUrl: string; querySettings: IQuerySettings; templateText?: string; templateUrl?: string; diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/loc/en-us.js b/samples/react-content-query-webpart/src/webparts/contentQuery/loc/en-us.js index e9e789ebc..1f0137786 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/loc/en-us.js +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/loc/en-us.js @@ -8,9 +8,13 @@ define([], function() { QueryGroupName: "Query", DisplayGroupName: "Display", ExternalGroupName: "External", + SiteUrlFieldLabel: "Site Url", + SiteUrlFieldPlaceholder: "Select the source site...", + SiteUrlFieldLoadingLabel: "Loading available site collections...", + SiteUrlFieldLoadingError: "An error occured while loading site collections : {0}", WebUrlFieldLabel: "Web Url", WebUrlFieldPlaceholder: "Select the source web...", - WebUrlFieldLoadingLabel: "Loading webs from current site...", + WebUrlFieldLoadingLabel: "Loading webs from selected site...", WebUrlFieldLoadingError: "An error occured while loading webs : {0}", ListTitleFieldLabel: "List Title", ListTitleFieldPlaceholder: "Select the source list...", diff --git a/samples/react-content-query-webpart/src/webparts/contentQuery/loc/mystrings.d.ts b/samples/react-content-query-webpart/src/webparts/contentQuery/loc/mystrings.d.ts index 47c9eb58e..f7e1928d7 100644 --- a/samples/react-content-query-webpart/src/webparts/contentQuery/loc/mystrings.d.ts +++ b/samples/react-content-query-webpart/src/webparts/contentQuery/loc/mystrings.d.ts @@ -7,6 +7,10 @@ declare interface IContentQueryStrings { QueryGroupName: string; DisplayGroupName: string; ExternalGroupName: string; + SiteUrlFieldLabel: string; + SiteUrlFieldPlaceholder: string; + SiteUrlFieldLoadingLabel: string; + SiteUrlFieldLoadingError: string; WebUrlFieldLabel: string; WebUrlFieldPlaceholder: string; WebUrlFieldLoadingLabel: string;