{
data-selection-index={index}
data-is-focusable={(enableTermFocusInDisabledPicker || !disabled) && true}
>
-
+
{children}
= (props: Rea
className,
selectedSites,
trimDuplicates,
- additionalQuery
+ additionalQuery,
+ hubsiteId
} = props;
const [isLoading, setIsLoading] = React.useState();
@@ -233,11 +234,18 @@ export const SitePicker: React.FunctionComponent = (props: Rea
setFilteredSites([]);
let promise: Promise;
- if (mode === 'hub') {
- promise = getHubSites(context);
- }
- else {
- promise = getAllSites(context, mode !== 'site', limitToCurrentSiteCollection, trimDuplicates === true, additionalQuery);
+ switch (mode) {
+ case 'hub':
+ promise = getHubSites(context);
+ break;
+
+ case 'associatedsites':
+ promise = getAssociatedSites(context, trimDuplicates === true, hubsiteId);
+ break;
+
+ default:
+ promise = getAllSites(context, mode !== 'site', limitToCurrentSiteCollection, trimDuplicates === true, additionalQuery);
+ break;
}
promise.then(newSites => {
diff --git a/src/controls/sitePicker/index.ts b/src/controls/sitePicker/index.ts
index 5f4714234..a08b0182a 100644
--- a/src/controls/sitePicker/index.ts
+++ b/src/controls/sitePicker/index.ts
@@ -1,2 +1,3 @@
export * from './ISitePicker';
export * from './SitePicker';
+export { ISite } from '../../services/SPSitesService';
diff --git a/src/controls/taxonomyPicker/TermPicker.tsx b/src/controls/taxonomyPicker/TermPicker.tsx
index 1d4a76cf2..923a8de0d 100644
--- a/src/controls/taxonomyPicker/TermPicker.tsx
+++ b/src/controls/taxonomyPicker/TermPicker.tsx
@@ -154,7 +154,9 @@ export default class TermPicker extends React.Component {
"DynamicFormLoading": "Laden...",
"DynamicFormPleaseWait": "Bitte warten...",
"DynamicFormRequiredErrorMessage": "Sie können dieses Feld nicht leer lassen.",
- "DynamicFormTermPanelTitle": "Laufzeit auswählen",
+ "DynamicFormTermPanelTitle": "Knoten auswählen",
"DynamicFormEnterURLPlaceholder": "Geben Sie eine URL ein",
"DynamicFormEnterDescriptionPlaceholder": "Alternativtext",
"customDisplayName": "Verwenden Sie diesen Speicherort:",
diff --git a/src/services/FilesSearchService.ts b/src/services/FilesSearchService.ts
index 5bb9ab930..93e00daa2 100644
--- a/src/services/FilesSearchService.ts
+++ b/src/services/FilesSearchService.ts
@@ -4,6 +4,7 @@ import { ISearchResult, BingQuerySearchParams, IRecentFile } from "./FilesSearch
import { find } from "office-ui-fabric-react/lib/Utilities";
import { GeneralHelper } from "../common/utilities/GeneralHelper";
import type { IBingSearchResult } from '../controls/filePicker/WebSearchTab/IBingSearchResult';
+import { getSiteWebInfo } from './SPSitesService';
/**
* Maximum file size when searching
@@ -18,10 +19,12 @@ const MAXRESULTS = 100;
export class FilesSearchService {
private context: BaseComponentContext;
private bingAPIKey: string;
+ private siteAbsoluteUrl: string;
- constructor(context: BaseComponentContext, bingAPIKey: string) {
+ constructor(context: BaseComponentContext, bingAPIKey: string, siteAbsoluteUrl?: string) {
this.context = context;
this.bingAPIKey = bingAPIKey;
+ this.siteAbsoluteUrl = siteAbsoluteUrl || context.pageContext.web.absoluteUrl
}
/**
@@ -51,8 +54,13 @@ export class FilesSearchService {
*/
public executeRecentSearch = async (accepts?: string[]): Promise => {
try {
- const webId = this.context.pageContext.web.id.toString();
- const siteId = this.context.pageContext.site.id.toString();
+ let webId = this.context.pageContext.web.id.toString();
+ let siteId = this.context.pageContext.site.id.toString();
+ if (this.siteAbsoluteUrl !== this.context.pageContext.web.absoluteUrl) {
+ const siteinfo = await getSiteWebInfo(this.context, this.siteAbsoluteUrl);
+ webId = siteinfo.webId;
+ siteId = siteinfo.siteId;
+ }
const fileFilter = this._getFileFilter(accepts);
const queryTemplate: string = `((SiteID:${siteId} OR SiteID: {${siteId}}) AND (WebId: ${webId} OR WebId: {${webId}})) AND LastModifiedTime < {Today} AND -Title:OneNote_DeletedPages AND -Title:OneNote_RecycleBin${fileFilter}`;
@@ -96,7 +104,7 @@ export class FilesSearchService {
]
}
};
- const searchApi = `${this.context.pageContext.web.absoluteUrl}/_api/search/postquery`;
+ const searchApi = `${this.siteAbsoluteUrl}/_api/search/postquery`;
const recentSearchDataResult = await this.context.spHttpClient.post(searchApi, SPHttpClient.configurations.v1, {
headers: {
diff --git a/src/services/SPSitesService.ts b/src/services/SPSitesService.ts
index 0de2b4ccc..88a5369f3 100644
--- a/src/services/SPSitesService.ts
+++ b/src/services/SPSitesService.ts
@@ -1,11 +1,43 @@
import { BaseComponentContext } from '@microsoft/sp-component-base';
-import { ISite } from '../controls/sitePicker/ISitePicker';
import { SPHttpClient } from '@microsoft/sp-http';
+import { IHubSiteData } from '../common/Interfaces';
+
+export interface ISite {
+ /**
+ * ID of the site
+ */
+ id?: string;
+ /**
+ * Title
+ */
+ title?: string;
+ /**
+ * Base URL
+ */
+ url?: string;
+
+ /**
+ * ID of the web
+ */
+ webId?: string;
+
+ /**
+ * ID of the hub site
+ */
+ hubSiteId?: string;
+}
+
+export interface ISiteWebInfo {
+ title: string,
+ webId: string,
+ siteId: string
+}
const getAllSitesInternal = async (ctx: BaseComponentContext, queryText: string, trimDuplicates: boolean): Promise => {
let startRow = 0;
const rowLimit = 500;
let totalRows = 0;
+ let currentRows = 0;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const values: any[] = [];
@@ -39,8 +71,9 @@ const getAllSitesInternal = async (ctx: BaseComponentContext, queryText: string,
values.push(...relevantResults.Table.Rows);
totalRows = relevantResults.TotalRows;
startRow += rowLimit;
+ currentRows = relevantResults.Table.Rows?.length;
- } while (values.length < totalRows);
+ } while (values.length < totalRows && currentRows !== 0);
// Do the call against the SP REST API search endpoint
@@ -113,3 +146,43 @@ export const getHubSites = async (ctx: BaseComponentContext): Promise =
return hubSites;
};
+
+export const getSiteWebInfo = async (ctx: BaseComponentContext, webUrl: string): Promise => {
+ const webInfo = await ctx.spHttpClient.get(`${webUrl}/_api/web?$select=id,Title`, SPHttpClient.configurations.v1);
+ if (!webInfo || !webInfo.ok) {
+ throw new Error(`[FileBrowser.getWebInfo]: Something went wrong when executing request. Status='${webInfo.statusText}'`);
+ }
+ const siteInfo = await ctx.spHttpClient.get(`${webUrl}/_api/site?$select=id`, SPHttpClient.configurations.v1);
+ if (!siteInfo || !siteInfo.ok) {
+ throw new Error(`[FileBrowser.getWebInfo]: Something went wrong when executing request. Status='${webInfo.statusText}'`);
+ }
+ const webInfoResult = await webInfo.json();
+ const siteInfoResult = await siteInfo.json();
+ return {
+ title: webInfoResult.Title,
+ webId: webInfoResult.Id,
+ siteId: siteInfoResult.Id
+ };
+}
+
+export const getAssociatedSites = async (ctx: BaseComponentContext, trimDuplicates: boolean, hubSiteId?: string): Promise => {
+ if (!hubSiteId){
+
+ const requestUrl = `${ctx.pageContext.site.absoluteUrl}/_api/web/HubsiteData`;
+ const response = await ctx.spHttpClient.get(requestUrl, SPHttpClient.configurations.v1);
+ const json = await response.json();
+
+ const hubsiteData: IHubSiteData = JSON.parse(json.value);
+
+ if (hubsiteData === null)
+ return [];
+
+ hubSiteId = hubsiteData.relatedHubSiteIds[0];
+
+ }
+
+ const queryText = `(contentclass:STS_Site DepartmentId:${hubSiteId})`;
+
+
+ return getAllSitesInternal(ctx, queryText, trimDuplicates);
+};
\ No newline at end of file
diff --git a/src/services/SPTermStorePickerService.ts b/src/services/SPTermStorePickerService.ts
index f17a51d6c..23dca8bad 100644
--- a/src/services/SPTermStorePickerService.ts
+++ b/src/services/SPTermStorePickerService.ts
@@ -29,7 +29,7 @@ export default class SPTermStorePickerService {
*/
constructor(private props: ITaxonomyPickerProps, private context: BaseComponentContext) {
this.clientServiceUrl = this.context.pageContext.web.absoluteUrl + '/_vti_bin/client.svc/ProcessQuery';
- this.suggestionServiceUrl = this.context.pageContext.web.absoluteUrl + "/_vti_bin/TaxonomyInternalService.json/GetSuggestions";
+ this.suggestionServiceUrl = this.context.pageContext.web.absoluteUrl + '/_vti_bin/TaxonomyInternalService.json/GetSuggestions';
}
public async getTermLabels(termId: string): Promise {
@@ -389,8 +389,8 @@ export default class SPTermStorePickerService {
anchorId: this.props.anchorId ? this.props.anchorId : EmptyGuid,
isSpanTermStores: false,
isSpanTermSets: false,
- isIncludeUnavailable: this.props.hideTagsNotAvailableForTagging === true,
- isIncludeDeprecated: this.props.hideDeprecatedTags === true,
+ isIncludeUnavailable: this.props.hideTagsNotAvailableForTagging !== true,
+ isIncludeDeprecated: this.props.hideDeprecatedTags !== true,
isAddTerms: false,
isIncludePathData: false,
excludeKeyword: false,
diff --git a/src/webparts/controlsTest/components/ControlsTest.tsx b/src/webparts/controlsTest/components/ControlsTest.tsx
index 9845415bd..13b20eee1 100644
--- a/src/webparts/controlsTest/components/ControlsTest.tsx
+++ b/src/webparts/controlsTest/components/ControlsTest.tsx
@@ -190,6 +190,7 @@ import { ControlsTestEnhancedThemeProvider, ControlsTestEnhancedThemeProviderFun
import { AdaptiveCardDesignerHost } from "../../../AdaptiveCardDesignerHost";
import { ModernAudio, ModernAudioLabelPosition } from "../../../ModernAudio";
import { SPTaxonomyService, TaxonomyTree } from "../../../ModernTaxonomyPicker";
+import { TestControl } from "./TestControl";
// Used to render document card
@@ -1702,8 +1703,8 @@ export default class ControlsTest extends React.Component
alert(JSON.stringify(action))}
- onError={(error) => alert(error.message)}
+ onError={(error) => console.log(error.message)}
onSetCustomElements={(registry: CardObjectRegistry) => { }}
onSetCustomActions={(registry: CardObjectRegistry) => { }}
onUpdateHostCapabilities={(hostCapabilities: HostCapabilities) => {
@@ -2408,6 +2409,11 @@ export default class ControlsTest extends React.Component
+
+
Monaco Editor
+
+
+
);
}
diff --git a/tsconfig.json b/tsconfig.json
index d3fea1c39..f9e3ddde8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -34,5 +34,5 @@
"src/**/*.ts",
"src/**/*.tsx"
],
- "exclude": ["**/node_modules", "**/dist", "**/lib"],
+ "exclude": ["**/node_modules", "**/dist", "**/lib"]
}