@microsoft/sp-webpart-base
Version:
SharePoint Framework support for building web parts
913 lines • 113 kB
JavaScript
"use strict";
/* eslint-disable max-lines */
// Copyright (c) Microsoft. All rights reserved.
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var sp_component_base_1 = require("@microsoft/sp-component-base");
var sp_core_library_1 = require("@microsoft/sp-core-library");
var sp_diagnostics_1 = require("@microsoft/sp-diagnostics");
var sp_http_1 = require("@microsoft/sp-http");
var sp_loader_1 = require("@microsoft/sp-loader");
var lodash = tslib_1.__importStar(require("@microsoft/sp-lodash-subset"));
var sp_page_context_1 = require("@microsoft/sp-page-context");
var loadThemedStyles = tslib_1.__importStar(require("@microsoft/load-themed-styles"));
var PropertyPaneLoader_1 = tslib_1.__importDefault(require("../PropertyPaneLoader"));
var ExecuteWithoutFailing_1 = require("../utils/ExecuteWithoutFailing");
var KillSwitches_1 = require("../common/KillSwitches");
var Flights_1 = require("../common/Flights");
var BaseClientSideWebPart_1 = tslib_1.__importDefault(require("./BaseClientSideWebPart"));
var ClassicPageUtils_1 = tslib_1.__importDefault(require("./classicPages/ClassicPageUtils"));
var ClientSideWebPartStatusRenderer_1 = tslib_1.__importDefault(require("./ClientSideWebPartStatusRenderer"));
var SPWebPartError_1 = require("./error/SPWebPartError");
var IWebPartData_1 = require("./IWebPartData");
var IframedWebPartControllerLoader_1 = tslib_1.__importDefault(require("./loaders/IframedWebPartControllerLoader"));
var WebPartContext_1 = tslib_1.__importDefault(require("./WebPartContext"));
var WebPartFormFactor_1 = require("./WebPartFormFactor");
var Strings_resx_1 = tslib_1.__importDefault(require("./loc/Strings.resx"));
var WebPartWidthCacheManager_1 = tslib_1.__importDefault(require("./WebPartWidthCacheManager"));
var Enums_1 = require("../common/Enums");
var constants_1 = require("../common/constants");
var getErrorAceLoadConfiguration_1 = require("../utils/getErrorAceLoadConfiguration");
var isWebPartData_1 = require("../utils/isWebPartData");
var WebPartIdleLoad_1 = require("./idleLoad/WebPartIdleLoad");
var THUMBNAIL_MAX_URL_LENGTH = 255; // All SharePoint URL field types have this limit
var DOCVIZ_REGEX = /(\/_layouts\/15\/getpreview.ashx\/?(|(\?(.*?)))$)/i;
// Flight name is 'SppplatIframedWebPartControllerLoadingFeature'
var SPPPLAT_IFRAMED_WEBPART_CONTROLLER_FLIGHT_ID = 1147;
var ISOLATED_ACE_WP_MANIFEST_ID = 'e6b93447-8007-4f1e-934f-754a0031a769';
var IMAGE_WEBPART_V1_MANIFEST_ID = 'd1d91016-032f-456d-98a4-721247c305e8';
var IMAGE_WEBPART_V2_MANIFEST_ID = 'fe2f2812-4df0-42c7-ae2e-2db57e092751';
var LIST_WEBPART_V1_MANIFEST_ID = 'f92bf067-bc19-489e-a556-7fe95f508720';
var LIST_WEBPART_V2_MANIFEST_ID = 'a572f711-58d9-473f-a827-ac3ffd529516';
var LIST_WEBPART_FILEBROWSER_MANIFEST_ID = 'da46359b-3267-4af8-9c8e-42c631ae31c0';
var LOAD_ISOLATED_WEBPART = 'LoadIsolatedWebPart';
var PREFAB_WEBPART_MANIFEST_ID = 'a0957e08-a450-4de0-b402-7db1bd92c4de';
/**
* The ClientSideWebPartManager is expected to be the public interface to client-side web parts. Each
* host is expected to create an instance of this class and manage loading of all web parts in that host
* through that one instance. e.g. On one page, if there are multiple Canvas objects, each one could have
* one instance of this class. If the page hosts web parts without the Canvas, then the page can have an
* instance of this class. Overall this class is expected to provide the following purpose:
*
* - Orchestrates loading of one or more web parts in a host.
* - It takes care of loading web part dependencies asynchronously. Each web part loads completely
* independently of the other web parts in the host.
* - Keep a reference to all the loaded web parts and help provide bulk operations on the web parts.
* - Help manage memory leak type issues in one place.
* - Integrate the web parts with the PropertyPane and other external entities.
* - Help troubleshoot web parts during escalations.
*
* @internal
*/
var ClientSideWebPartManager = /** @class */ (function () {
/**
* Initialize the ClientSideWebPartManager.
*
* @param host - Reference to the host. A web part host is a component that is deemed capable of hosting a web
* part. Any component that implements the IWebPartHost is allowed to host a web part.
*/
function ClientSideWebPartManager(host) {
/**
* Dictionary of all the active web parts in this instance of the manager.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this._webParts = new Map();
/**
* Web part status renderer instance scoped to this web part manager instance.
*/
this._statusRenderer = new ClientSideWebPartStatusRenderer_1.default();
/**
* Dictionary of all the iframed web parts in this instance of the manager.
*/
this._iframedWebpartInstanceIds = new Set();
this._propertyPaneConsumerQueue = new Map();
this._displayMode = sp_core_library_1.DisplayMode.Read;
sp_core_library_1.Validate.isNotNullOrUndefined(host, 'host');
this._host = host;
this._pageContext = host.serviceScope.consume(sp_page_context_1.PageContext.serviceKey);
this._onContainerResize = this._onContainerResize.bind(this);
this._onPropertyPaneNotifications = this._onPropertyPaneNotifications.bind(this);
this.requestPropertyPaneAction = this.requestPropertyPaneAction.bind(this);
this.isPropertyPaneRenderedByWebPart = this.isPropertyPaneRenderedByWebPart.bind(this);
this.isPropertyPaneOpen = this.isPropertyPaneOpen.bind(this);
if (ClientSideWebPartManager._webPartManagerList.length === 0) {
this._initialzeOnResizeEventHandler();
}
ClientSideWebPartManager._webPartManagerList.push(this);
}
/**
* Create the web part tag. Web part tag is a unique tag per web part instance and is used for logging and telemetry.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ClientSideWebPartManager.createWebPartTag = function (manifest, instanceId) {
return "WebPart.".concat(manifest.alias, ".").concat(manifest.isInternal ? 'internal' : 'external', ".").concat(instanceId);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ClientSideWebPartManager._instanceOfBase = function (wp) {
if (!wp) {
return false;
}
else if (wp instanceof BaseClientSideWebPart_1.default) {
return true;
}
else {
var objectType = wp['__type'];
return objectType === 'BaseClientSideWebPart' || objectType === 'BaseMRClientSideWebPart';
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ClientSideWebPartManager._getWebPartTag = function (wp) {
var errorReason;
if (!ClientSideWebPartManager._instanceOfBase(wp)) {
errorReason = 'WebpartTag requested for non-webpart';
}
else if (!wp.context) {
// wp not being defined is checked by _instanceOfBase
errorReason = 'WebpartTag requested for instance that is missing context';
}
if (errorReason) {
sp_diagnostics_1._TraceLogger.logError(ClientSideWebPartManager._logSource, new Error(errorReason));
return undefined;
}
return wp.context.webPartTag;
};
ClientSideWebPartManager._isLoadingIsolatedWebPart = function (context, siteUrl) {
var manifest = context.manifest, pageLayoutType = context.pageLayoutType;
if ((0, Flights_1.is1PIsolationEnabled)() && manifest.isInternal && manifest.isolationLevel === 'DomainIsolation') {
var tenantName = siteUrl.match(ClientSideWebPartManager._1PIsolatedDomainRegex);
if (tenantName) {
// The special app domain is constant for each tenant
// This code will need to be updated when we fix vanity domain issues with isolated domains
manifest.isolatedDomain = new URL(siteUrl.replace(ClientSideWebPartManager._1PIsolatedDomainRegex, "".concat(tenantName[0], "-app3bc2296eaa224ed29e1e946d05afa6a2"))).hostname;
}
else if (pageLayoutType !== 'Isolated') {
throw new Error("Cannot create isolated domain for: ".concat(siteUrl));
}
}
return (sp_core_library_1._SPFlight.isEnabled(SPPPLAT_IFRAMED_WEBPART_CONTROLLER_FLIGHT_ID) &&
// The next condition is neccessary because the same web part
// will cross this path twice, once when determining if we should load in an
// iframe and the second time is when we are loading the web part inside
// the iframe.
pageLayoutType !== 'Isolated' &&
(manifest.isolationLevel === IWebPartData_1.WebPartIsolationLevel.DomIsolation ||
// 'isolatedDomain' is a string and we want to check if 'isolatedDomain' has value,
// instead of undefined or "".
!!manifest.isolatedDomain));
};
ClientSideWebPartManager._getWebPartTitle = function (manifest, webPartData) {
// If the web part has data, take the title from the data.
var title = webPartData && webPartData.title;
if (!title) {
// If the web part has just been created from the Toolbox, use the title from the picked up entry.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
title = manifest.title && manifest.title.default;
}
// If we still do not have a title use the title from the preconfigured entries
return title || manifest.preconfiguredEntries[0].title.default;
};
ClientSideWebPartManager._loadDynamicComponentDependencies = function (components, webPartData, webPartTag) {
var componentDependencies = (webPartData.serverProcessedContent && webPartData.serverProcessedContent.componentDependencies) || {};
var dependencies = Object.keys(componentDependencies);
for (var _i = 0, dependencies_1 = dependencies; _i < dependencies_1.length; _i++) {
var dep = dependencies_1[_i];
var componentId = componentDependencies[dep];
if (sp_core_library_1.Guid.isValid(componentId)) {
components.push(sp_loader_1.SPComponentLoader.loadComponentById(componentId));
}
else {
throw new Error("Failed to load web part's (".concat(webPartTag, ") dynamic dependency ").concat(dep, " with component id {").concat(componentId, "}"));
}
}
};
Object.defineProperty(ClientSideWebPartManager, "isMaintenanceMode", {
/**
* Returns true if the maintenanceMode query string parameter is provided.
*/
get: function () {
var urlParams = new sp_core_library_1.UrlQueryParameterCollection(window.location.href);
return urlParams.getValue('maintenanceMode') === 'true';
},
enumerable: false,
configurable: true
});
/**
* Enables prefetching for the specified set of web parts.
*
* @privateRemarks
* This is a prerequiste for prefetching and it does not initiate prefetching.
* You must call `prefetchWebParts` to start the prefetching process (see example below).
*
* Example:
* ```
* ClientSideWebpartManager.webPartPrefetching?.then((prefetching) =>
* prefetching.prefetchWebParts()
* );
* ```
* @param controls - The web parts to enable prefetching for.
* @beta
*/
ClientSideWebPartManager.prototype.enablePrefetching = function (controls) {
if (!(0, Flights_1.isLoadEditModeWebPartsInParallelEnabled)()) {
return;
}
var prefetchingModule = this._loadWebPartPrefetching();
prefetchingModule === null || prefetchingModule === void 0 ? void 0 : prefetchingModule.enablePrefetching(controls);
};
/**
* Load a web part in the provided DOM element. Does the following steps
*
* 1. Validate params.
* 2. Validate the web part manifest.
* 3. Perform an async import of the web part modules from the provided manifest
* - i.e ClientSideWebPartManager._loadComponentModules
* 4. Instantiate and initialize the web part object
* - i.e. ClientSideWebPartManager._initializeWebPart
* 5. Render the web part in the provided DOM element
* - i.e. ClientSideWebPartManager._renderWebPart
*
* If an error happens during any of the above steps, catch the error and log it.
*
* @param webPartManagerContext - web part manager context.
*/
ClientSideWebPartManager.prototype.loadWebPart = function (webPartManagerContext) {
var _this = this;
try {
if ((0, KillSwitches_1.isRefactorLoadWebPartKSActivated)()) {
return this._loadWebPartOld(webPartManagerContext);
}
var context_1 = webPartManagerContext;
var isIsolated_1 = this._isIsolatedWebPart(context_1);
var monitor_1 = new sp_diagnostics_1._QosMonitor('WebPart.Load', true);
var loadError_1;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var webPartInstance_1;
return (this._loadAndInitWebPart(context_1)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.then(function (response) {
// if isolated webpart loaded successfully exit the promise chain
if (response === LOAD_ISOLATED_WEBPART) {
return Promise.reject(new Error(LOAD_ISOLATED_WEBPART));
}
_this._validateIfWPIsNotDisposed(response);
_this._host.onBeforeWebPartRender(context_1);
loadThemedStyles.flush();
return response;
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.then(function (webPart) {
_this._validateIfWPIsNotDisposed(webPart);
if (!(0, KillSwitches_1.isHandleDisposeRaceConditionKSActive)()) {
webPartInstance_1 = webPart;
}
return _this._loadPropertyPaneModule(webPart);
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.then(function (webPart) {
_this._validateIfWPIsNotDisposed(webPart);
return _this._renderWebPart(webPart);
})
.then(function (_a) {
var webPart = _a.webPart, renderCompleteTime = _a.renderCompleteTime;
context_1.renderCompleteTime = renderCompleteTime;
if (!(0, KillSwitches_1.isIsolatedAdaptiveCardExtensionIframedPropertyPaneKSActivated)() &&
isIsolated_1 &&
context_1.manifest.id === ISOLATED_ACE_WP_MANIFEST_ID) {
if (_this._iframedWebPartController) {
_this._iframedWebPartController.assignIsolatedACEWP(context_1.instanceId, webPart);
}
}
_this._host.onAfterWebPartRender(context_1);
ClassicPageUtils_1.default.removeFabricLinks();
return _this._loadLegacyFabricCssIfRequired(context_1);
})
.catch(function (error) {
if (error instanceof Error && error.message === LOAD_ISOLATED_WEBPART) {
return LOAD_ISOLATED_WEBPART;
}
if ('isDisposed' in error) {
// IWebPartDisposedError
error.stage = 'Render';
throw error;
}
if (!loadError_1) {
loadError_1 = {
error: error,
stage: 'Render'
};
}
throw loadError_1;
})
.then(function (response) {
if (response === LOAD_ISOLATED_WEBPART) {
return;
}
var extraData = sp_component_base_1._WebPartLoadDataCollector.collect(context_1.manifest, context_1.webPartTag, _this._pageContext);
monitor_1.writeSuccess(extraData);
})
.catch(function (e) {
var extraData = sp_component_base_1._WebPartLoadDataCollector.collect(context_1.manifest, context_1.webPartTag, _this._pageContext);
if (!(0, KillSwitches_1.isLogWebPartLoadErrorKSActivated)() && !(e.error instanceof Error)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
extraData.errorData = e.error;
}
if ('isDisposed' in e || (webPartInstance_1 === null || webPartInstance_1 === void 0 ? void 0 : webPartInstance_1.isDisposed)) {
// IWebPartDisposedError
monitor_1.writeExpectedFailure(e.stage, e.error, extraData);
_this._statusRenderer.clearLoadingIndicator(context_1.domElement);
}
else {
monitor_1.writeUnexpectedFailure(e.stage, e.error, extraData);
var error = e.error, stage = e.stage;
switch (stage) {
case 'Load':
_this._host.onAfterWebPartLoadFailed(context_1, error);
break;
case 'Initialize':
_this._host.onAfterWebPartInitializeFailed(context_1, error);
break;
case 'Render':
_this._host.onAfterWebPartRenderFailed(context_1, error);
break;
}
var instanceId = context_1.instanceId;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var errorWebPart = _this._webParts.get(instanceId);
if (errorWebPart) {
errorWebPart.dispose();
_this._webParts.delete(instanceId);
}
var additionalMessage = '';
if (errorWebPart === null || errorWebPart === void 0 ? void 0 : errorWebPart.modifiedByGraph) {
var date = new Date((errorWebPart === null || errorWebPart === void 0 ? void 0 : errorWebPart.modifiedByGraph.lastModified) * 1000);
additionalMessage = sp_core_library_1.Text.format(Strings_resx_1.default.WebpartErrorPagesAPIRelated, errorWebPart === null || errorWebPart === void 0 ? void 0 : errorWebPart.modifiedByGraph.apiVersion, date.toLocaleDateString(), date.toLocaleTimeString());
}
_this._statusRenderer.renderError(context_1.domElement, error, {
message: additionalMessage
});
throw e.error;
}
}));
}
catch (error) {
return Promise.reject(error);
}
};
/**
* Set a IPropertyPaneConsumer object into the set of the Client-side Web Part Manager's
* managed web parts.
*
* @param id - A unique instance id.
* @param control - A component which wants to use the property Pane.
*
* @internal
*/
ClientSideWebPartManager.prototype.setPropertyPaneConsumer = function (id, control) {
sp_core_library_1.Validate.isNonemptyString(id, 'id');
sp_core_library_1.Validate.isNotNullOrUndefined(control, 'control');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this._webParts.set(id, control);
this._registerWebPartAsPropertyPaneConsumer(id);
};
/**
* Fetch web part manifests. This makes a REST call to load the current site's web parts into the module loader.
*
* Previously, this method only fetched WebPart manifests through a REST call to GetClientSideWebParts
* Then, an extra call to fetch AdaptiveCardExtension manifests via GetAdaptiveCardExtensions was added when MEEDashboard is enabled
*
* To consolidate these calls into a single request, we use a new endpoint, GetClientSideComponentsByComponentType
*
* If the CallGetClientSideComponentsByComponentType flight is enabled
* - call GetClientSideComponentsByComponentType(["WebPart", "AdaptiveCardExtension"]) if MEEDashboard flight enabled
* - call GetClientSideWebParts, since GetClientSideComponentsByComponentType server endpoint checks for MEEDashboard flight: Workitem 1119156
* If the CallGetClientSideComponentsByComponentType flight is disabled
* - call GetClientSideWebParts and GetAdaptiveCardExtensions if MEEDashboard flight is enabled
* - call GetClientSideWebParts, only, if MEEDashboard flight is disabled
*
* This method will also initiate fetching of Teams-connected manifests from Teams App Catalog.
*/
ClientSideWebPartManager.prototype.fetchWebPartManifests = function () {
var _this = this;
var shouldFetchACEs = !(0, Flights_1.isOptionalSupportedHostsFilteringEnabled)();
if (shouldFetchACEs) {
this._toolboxACEManifestsPromise = this._fetchAdaptiveCardExtensionManifests();
}
if (!this._toolboxManifestsPromise &&
// If the webServerRelativeUrl is missing we don't have anything to do here.
(!this._pageContext.web ||
!this._pageContext.web.serverRelativeUrl ||
sp_core_library_1.Environment.type === sp_core_library_1.EnvironmentType.Local ||
sp_core_library_1.Environment.type === sp_core_library_1.EnvironmentType.Test)) {
this._toolboxManifestsPromise = Promise.resolve();
}
// if web parts have already been fetched we don't have anything to do here.
if (!this._toolboxManifestsPromise) {
var requestCorrelationId_1;
var fromServiceWorker_1;
var qosMonitor_1 = new sp_diagnostics_1._QosMonitor('ClientSideWebPartManager.FetchWebParts');
var endpoint = void 0;
if ((0, Flights_1.isOptionalSupportedHostsFilteringEnabled)()) {
endpoint = "_api/web/GetClientSideComponentsByComponentType(componentTypesString='".concat(Enums_1.SPClientSideComponentType.WebPart, ",").concat(Enums_1.SPClientSideComponentType.AdaptiveCardExtension, "', includeManifestActivatedTime=true)");
}
else {
// ACEs will be fetched in another request
endpoint = "_api/web/GetClientSideComponentsByComponentType(componentTypesString='".concat(Enums_1.SPClientSideComponentType.WebPart, "',supportedHostTypeValue=").concat(Enums_1.SupportedHostType.SharePointWebPart, ")");
}
var requestUrl_1 = "".concat(sp_core_library_1.UrlUtilities.removeEndSlash(this._pageContext.web.serverRelativeUrl), "/").concat(endpoint);
this._host.serviceScope.whenFinished(function () {
var httpClient = _this._host.serviceScope.consume(sp_http_1.SPHttpClient.serviceKey);
_this._toolboxManifestsPromise = _this._fetchManifestsWithCache(httpClient, requestUrl_1)
.then(function (response) {
requestCorrelationId_1 = response.correlationId ? response.correlationId.toString() : undefined;
fromServiceWorker_1 = response.headers.get('X-From-Service-Worker') === 'true';
if (response.ok) {
return (response.jsonCached ||
(response.jsonCached = Promise.resolve(response.json())));
}
else {
throw SPWebPartError_1.SPWebPartError.create(SPWebPartError_1.SPWebPartErrorCode.ManifestDownloadFailed);
}
})
.then(function (value) {
var manifests = value.value.map(function (manifestObject) {
var parsedManifest = JSON.parse(manifestObject.Manifest);
if (manifestObject.ManifestActivatedTime) {
parsedManifest.manifestActivatedTime = manifestObject.ManifestActivatedTime;
}
return parsedManifest;
});
_this._disambiguateWebPartManifestLocales(manifests);
// Ideally we always want to refresh manifests to get rid of stale manifests which might not be installed
// in the current site (after cross-sites navigation). However, in debug mode, manifests are not marked as
// "isInternal: true" which causes them being removed by refreshWebPartManifests
if (!(0, KillSwitches_1.isWebPartManifestListCacheRefreshKSActivated)() &&
!_this._isDebugSession &&
!sp_core_library_1._BrowserUtilities.isWorkbenchHosted()) {
sp_loader_1.SPComponentLoader.refreshWebPartManifests(manifests);
}
else {
sp_loader_1.SPComponentLoader.registerManifests(manifests);
}
qosMonitor_1.writeSuccess();
})
.catch(function (error) {
// Clear out the promise so we can try again if we enter edit mode again.
_this._toolboxManifestsPromise = undefined;
_this._clearManifestCacheItem(requestUrl_1);
sp_diagnostics_1._TraceLogger.logErrorData({
source: ClientSideWebPartManager._logSource,
error: error,
serviceScope: _this._host.serviceScope
});
qosMonitor_1.writeUnexpectedFailure('Rejected', error, {
correlationId: requestCorrelationId_1,
fromServiceWorker: fromServiceWorker_1
});
throw error;
});
});
}
var fetchTeamsAcePromise = this._fetchTeamsACEManifests(); // logic with all checks is included inside the method
var resultPromise;
if (shouldFetchACEs) {
resultPromise = Promise.all([
this._toolboxACEManifestsPromise,
this._toolboxManifestsPromise,
fetchTeamsAcePromise
]).then(function () { return undefined; });
}
else {
if (!(0, KillSwitches_1.isUsePromiseAllForFetchWebPartsKSActivated)()) {
// adding extra KS here as we're changing behavior to Promise.all - just for extra safety
resultPromise = Promise.all([this._toolboxManifestsPromise, fetchTeamsAcePromise]).then(function () { return undefined; });
}
else {
resultPromise = this._toolboxManifestsPromise;
}
}
return resultPromise;
};
/**
* Get list of active web part manifests.
*
* @param includeAdaptiveCardExtensions - Include ACE manifests (casted as webpart manifests) in the returned array.
*
* @returns - array of manifests.
*/
ClientSideWebPartManager.prototype.getWebPartManifests = function (includeAdaptiveCardExtensions) {
var _a;
if (includeAdaptiveCardExtensions === void 0) { includeAdaptiveCardExtensions = false; }
var manifests = sp_loader_1.SPComponentLoader._getManifestReferences();
var result = [];
for (var _i = 0, manifests_1 = manifests; _i < manifests_1.length; _i++) {
var manifest = manifests_1[_i];
// Some 1P ACEs are currently using web part manifests
// Remove this check after converting all the 1P manifests
var isWebPartACE = (_a = manifest.experimentalData) === null || _a === void 0 ? void 0 : _a.ACE;
if (manifest.componentType === 'WebPart' && !isWebPartACE) {
result.push(manifest);
}
else if (includeAdaptiveCardExtensions &&
(manifest.componentType === 'AdaptiveCardExtension' || isWebPartACE)) {
result.push(manifest);
}
}
return result;
};
/**
* Get list of Adaptive Card Extension manifests.
*
* @returns - array of ACE manifests
*/
ClientSideWebPartManager.prototype.getAdaptiveCardExtensionManifests = function () {
var _a, _b;
var manifests = sp_loader_1.SPComponentLoader._getManifestReferences();
var result = [];
//
// Currently we treat Teams App Catalog as the point of truth if the same component is available in both catalogs.
// So we need to add Teams ACEs first and then add missing ones from SharePoint.
// This will change if/when we implement sync Timer Job
//
if ((0, Flights_1.isBotAcesFromTeamsEnabled)() && this._toolboxTeamsAppComponentsManifests) {
result.push.apply(result, Array.from(this._toolboxTeamsAppComponentsManifests.values()));
}
for (var _i = 0, manifests_2 = manifests; _i < manifests_2.length; _i++) {
var manifest = manifests_2[_i];
if ((manifest.componentType === 'AdaptiveCardExtension' ||
((_a = manifest.experimentalData) === null || _a === void 0 ? void 0 : _a.ACE)) &&
!((_b = this._toolboxTeamsAppComponentsManifests) === null || _b === void 0 ? void 0 : _b.has(manifest.id)) && // we don't want to add items that have been already added
(!this._toolboxTeamsAppComponentsManifests ||
!manifest.connectedTeamsAppId) // we also don't want to add any Teams-connected ACEs in the toolbox. If they were not added from Teams App Catalog, either they were deleted or a user doesn't have permissions to see them
) {
result.push(manifest);
}
}
return result;
};
/**
* Set the display mode of the specified web part. If no web part id is specified, switch mode of all web parts.
* If the display mode passed is same as the current mode, no change is applied.
*
* @param displayMode - the new DisplayMode.
* @param instanceId - instance id of the web part.
*/
ClientSideWebPartManager.prototype.setDisplayMode = function (displayMode, instanceId) {
this._setDisplayMode(displayMode, instanceId).catch(function (e) {
return sp_diagnostics_1._TraceLogger.logVerboseData({
source: ClientSideWebPartManager._logSource,
message: e.message
});
});
};
/**
* @remarks
* Only use this API if you need to immediately call property pane APIs after switching the mode.
*
* @internal
*/
ClientSideWebPartManager.prototype._setDisplayMode = function (displayMode, instanceId) {
var _this = this;
this._displayMode = displayMode;
if (this._displayMode === sp_core_library_1.DisplayMode.Read) {
this._closeIsolatedPropertyPaneIfRequired();
}
// We only want to indicate we have loaded, if needed, the property pane
var setDisplayModePromise = this._loadPropertyPaneModuleOld();
// Set the display mode for the requested or all web parts.
this._executeForIdsOrAll(this._getArrayOrUndefined(instanceId), function (id, webPart) {
if (webPart) {
webPart._internalSetDisplayMode(displayMode);
}
else if (_this._iframedWebpartInstanceIds.has(id)) {
var qosMonitor = new sp_diagnostics_1._QosMonitor('ClientSideWebPartManager._setDisplayMode');
if (_this._iframedWebPartController) {
qosMonitor.writeSuccess();
_this._iframedWebPartController.setDisplayMode(displayMode, id);
}
else {
qosMonitor.writeUnexpectedFailure('iFrame controller used before deferral loading is complete');
}
}
});
// Start the dirty bit timer if required
this._startDirtyBitTimer(displayMode);
return setDisplayModePromise;
};
/**
* Serialize the specified web part. If no web part is specified, serialize all web parts.
*
* @param instanceId - instance id of the web part.
*/
ClientSideWebPartManager.prototype.serialize = function (instanceId) {
var _this = this;
var sd = new Map();
this._executeForIdsOrAll(this._getArrayOrUndefined(instanceId), function (id, webPart) {
if (webPart) {
sd.set(id, webPart._internalSerialize());
}
else if (_this._iframedWebpartInstanceIds.has(id)) {
sp_core_library_1.Validate.isNotNullOrUndefined(_this._iframedWebPartController, 'IFramedWebPartController is undefined');
sd.set(id, _this._iframedWebPartController.serialize(id));
}
});
return sd;
};
ClientSideWebPartManager.prototype.setWebPartData = function (contextOrWebPartData, instanceId, shouldFallback) {
if (shouldFallback === void 0) { shouldFallback = false; }
sp_core_library_1.Validate.isNotNullOrUndefined(contextOrWebPartData, 'web part manager context');
sp_core_library_1.Validate.isNonemptyString(instanceId, 'web part instance id');
var wp = this._webParts.get(instanceId);
var isWebPartDataUsed = !(0, KillSwitches_1.isClickToAddFromContentPaneKSActivated)() &&
(0, Flights_1.isConfigurationToolsEnabled)() &&
(0, isWebPartData_1.isWebPartData)(contextOrWebPartData);
var context = isWebPartDataUsed
? undefined
: contextOrWebPartData;
var webPartData = isWebPartDataUsed
? contextOrWebPartData
: context === null || context === void 0 ? void 0 : context.webPartData;
sp_core_library_1.Validate.isNotNullOrUndefined(webPartData, 'web part data');
if (wp && webPartData) {
if (shouldFallback && context) {
this.disposeWebparts(instanceId);
return this.loadWebPart(context);
}
else {
var addedFromPersistedData = isWebPartDataUsed ? false : !!(context === null || context === void 0 ? void 0 : context.addedFromPersistedData);
wp._internalSetWebPartData(webPartData, addedFromPersistedData);
sp_core_library_1._SPEventManager.instance.raiseEvent(this._getDataUpdatedEventName(webPartData.instanceId), {});
}
}
return Promise.resolve();
};
/**
* Dispose of the current webpart manager and all of the webparts it has loaded.
*/
ClientSideWebPartManager.prototype.dispose = function () {
this.disposeWebparts();
var currentIdx = ClientSideWebPartManager._webPartManagerList.indexOf(this);
if (currentIdx >= 0) {
ClientSideWebPartManager._webPartManagerList.splice(currentIdx, 1);
}
};
/**
* Dispose the specified web part. If no web part is specified, dispose all web parts.
*
* @param instanceId - instance id of the web part.
*/
ClientSideWebPartManager.prototype.disposeWebparts = function (instanceId) {
var _this = this;
this._executeForIdsOrAll(this._getArrayOrUndefined(instanceId), function (id, webPart) {
if (webPart) {
// Remove references to the web part from the manager before disposing it
_this._deleteWebPart(id);
// Actually dispose the web part
(0, ExecuteWithoutFailing_1.executeWithoutFailing)(function () {
webPart._internalDispose();
}, ClientSideWebPartManager._logSource);
}
else if (_this._iframedWebpartInstanceIds.has(id)) {
sp_core_library_1.Validate.isNotNullOrUndefined(_this._iframedWebPartController, 'IFramedWebPartController is undefined');
_this._iframedWebPartController.deleteWebPart(id);
}
});
};
/*
* Get the first web part with preview image url specified. If no web parts are specified, try to get the preview
* image from all web parts.
*
* @param instanceIds - instance ids of the web parts.
*/
ClientSideWebPartManager.prototype.tryGeneratePreviewImageUrl = function (instanceIds) {
var _this = this;
var candidatePreviewImageUrl;
var previewImageUrl = undefined;
var previewFromAlias = undefined;
var monitor = new sp_diagnostics_1._QosMonitor('ClientSideWebPartManager.tryGeneratePreviewImageUrl');
if (!(0, KillSwitches_1.isFixUnstableThumbnailKSActivated)()) {
this._webParts.forEach(function (webPart, instanceId) {
// Check the type because the dictionary can have web parts or property pane controls
if (ClientSideWebPartManager._instanceOfBase(webPart) &&
_this._isTitleAreaBannerWebPart(webPart) &&
webPart.previewImageUrl) {
previewImageUrl = webPart.previewImageUrl;
}
});
}
this._executeForIdsOrAll(instanceIds, function (instanceId, webPart) {
if (webPart) {
// workaround for typescript targeting es5 only support for...of for array and string
// also Map does not support some or every
// @todo: Bug 222340 when switching to es6, use for...of and return after first match
if (!previewImageUrl) {
var webPartThumbnail = webPart.previewImageUrl;
if (webPartThumbnail) {
previewFromAlias = webPart.context.manifest.alias;
if (webPartThumbnail.length < THUMBNAIL_MAX_URL_LENGTH) {
candidatePreviewImageUrl = webPartThumbnail;
// prefer non-canonical paths due to oAuth allowed end points
var normalizedPath = candidatePreviewImageUrl.toUpperCase();
// https://onedrive.visualstudio.com/_search?action=contents&text=authEndpoints&type=code&lp=custom-Collection&filters=ProjectFilters%7BOneDrive%20Service%7DRepositoryFilters%7Bnotify-server%7D&pageSize=25&result=DefaultCollection%2FOneDrive%20Service%2Fnotify-server%2FGBmaster%2F%2FActivity%2FOneDrive.Activity.DataAccess%2Fsrc%2FIdentity%2FSpoUserProvider.cs
var isSupportedByOAuth = DOCVIZ_REGEX.test(normalizedPath) || normalizedPath.indexOf('/_API/') >= 0;
if (isSupportedByOAuth ||
((0, KillSwitches_1.isFixUnstableThumbnailKSActivated)() && _this._isTitleAreaBannerWebPart(webPart))) {
previewImageUrl = candidatePreviewImageUrl;
}
}
else {
var imageUrl = webPart.previewImageUrl;
sp_diagnostics_1._TraceLogger.logVerboseData({
source: ClientSideWebPartManager._logSource,
eventName: 'tryGeneratePreviewImageUrl',
message: "".concat(previewFromAlias, " attempted preview URL of ").concat(imageUrl && imageUrl.length, " chars.")
});
}
}
}
}
else if (_this._iframedWebpartInstanceIds.has(instanceId)) {
// @todo: VSO#612911 - add support tryGeneratePreviewImageUrl for iframed webparts
monitor.writeExpectedFailure('IframedPart');
return undefined;
}
});
var extraData = monitor && previewFromAlias ? { alias: previewFromAlias } : undefined;
if (!previewImageUrl && candidatePreviewImageUrl) {
previewImageUrl = candidatePreviewImageUrl;
monitor.writeExpectedFailure('NonLayouts', undefined /* ex */, extraData);
}
if (!previewImageUrl && previewFromAlias) {
monitor.writeUnexpectedFailure('PathTooLong', undefined /* ex */, extraData);
// Ensure to adjust callers if changing this error message!
throw new Error('tryGeneratePreviewImageUrl PathLengthError.');
}
if (!monitor.hasEnded) {
monitor.writeSuccess(extraData);
}
return previewImageUrl;
};
/**
* Gets the top action configuration for the webpart with the specified instanceId
* @param instanceId - the specified instanceId
* @returns undefined if the webpart isn't loaded yet or the webpart doesn't support top actions.
*/
ClientSideWebPartManager.prototype.getWebpartTopActions = function (instanceId) {
var webPart = this._webParts.get(instanceId);
return webPart === null || webPart === void 0 ? void 0 : webPart.getTopActionsConfiguration();
};
/**
* Gets the accessibility results for the webpart with the specified instanceId
* @param instanceId - the specified instanceId
* @returns undefined if the webpart isn't loaded yet or the webpart doesn't support accessibility assistant.
*/
ClientSideWebPartManager.prototype.getWebpartA11yResult = function (instanceId) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var webPart, _i, _a, wpm;
return tslib_1.__generator(this, function (_b) {
for (_i = 0, _a = ClientSideWebPartManager._webPartManagerList; _i < _a.length; _i++) {
wpm = _a[_i];
webPart = wpm._webParts.get(instanceId);
if (webPart !== undefined) {
break;
}
}
if (webPart === undefined) {
return [2 /*return*/, Promise.resolve([undefined])];
}
return [2 /*return*/, webPart._checkA11y()];
});
});
};
/**
* Calls the preOnClickA11yResult method for the webpart with the specified instanceId
* to help users redirect to the specific item editing configuration pane to fix the accessibility issues.
* @param result - the accessibility result to be passed to the webpart
*/
ClientSideWebPartManager.prototype.preOnClickA11yResult = function (result) {
var webPart;
// if the the webPartInstanceId is not found, then return directly
if (!result.webPartInstanceId) {
return;
}
for (var _i = 0, _a = ClientSideWebPartManager._webPartManagerList; _i < _a.length; _i++) {
var wpm = _a[_i];
webPart = wpm._webParts.get(result.webPartInstanceId);
if (webPart !== undefined) {
break;
}
}
webPart === null || webPart === void 0 ? void 0 : webPart._preOnClickA11yResult(result);
};
/**
* Request property pane or content panel to perform the given action.
*
* @param instanceId - web part instance id.
* @param propertyPaneAction - indicates what action needs to be performed on the property pane.
* @param renderedByWebPart - indicates whether the the property pane rendered by a web part or not.
* @param context - pass additional context to property pane
*/
ClientSideWebPartManager.prototype.requestPropertyPaneAction = function (instanceId, propertyPaneAction, renderedByWebPart,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context) {
var _this = this;
var _a;
if (propertyPaneAction === void 0) { propertyPaneAction = 'Default'; }
if (this._iframedWebpartInstanceIds.has(instanceId)) {
// Iframe controller scenario
// Hiding the non-iframed property pane if open, before loading the iframed property pane.
if ((_a = this._propertyPane) === null || _a === void 0 ? void 0 : _a.isOpen((0, Flights_1.isConfigurationToolsEnabled)() ? instanceId : undefined)) {
this._propertyPane.requestAction(instanceId, 'Close', renderedByWebPart);
}
this._iframedWebPartController.requestPropertyPaneAction(propertyPaneAction, instanceId);
}
else {
var isHandledByWPHost = false;
if (this._host.requestPropertyPaneAction) {
// Allow web part host to handle the property pane action.
// For example, IFramedWebPartHost will post a message to the parent window to open the property pane.
isHandledByWPHost = this._host.requestPropertyPaneAction(instanceId, propertyPaneAction, renderedByWebPart, context);
}
if (!isHandledByWPHost) {
// Default scenario
// Hide the Iframed property pane before opening non-iframe scenario.
// if no iframed property pane is present then this is a no-op.
if (this._iframedWebPartController) {
this._iframedWebPartController.requestPropertyPaneAction('Close');
}
if (this._propertyPane) {
this._propertyPane.requestAction(instanceId, propertyPaneAction, renderedByWebPart, !(0, KillSwitches_1.isFixMissingContextKSActivated)() ? context : undefined);
}
else if (propertyPaneAction === 'OpenDetails') {
// If the properyPane is not loaded for OpenDetails Action,
// We have to load the property pane and then execute the action.
this._loadPropertyPaneModuleOld(true)
.then(function () {
return _this._propertyPane.requestAction(instanceId, propertyPaneAction, renderedByWebPart, context);
})
.catch(function (e) {
return sp_diagnostics_1._TraceLogger.logVerboseData({
source: ClientSideWebPartManager._logSource,
message: e.message
});
});
}
}
}
};
/**
* Returns true if the current property pane or content panel source is a web part and not the Canvas or any other source.
*/
ClientSideWebPartManager.prototype.isPropertyPaneRenderedByWebPart = function () {
return !!this._propertyPane && this._propertyPane.isRenderedByConsumer();
};
/**
* Returns the state of the PropertyPane if it is open or not.
* Also true if Property Pane is rendered by Content Panel.
*
* @param instanceId - optional param to check isopen based on the supported consumer (content panel or property pane).
* see IConfigurableOptionsController.isOpen(instanceId) for more details
*/
ClientSideWebPartManager.prototype.isPropertyPaneOpen = function (instanceId) {
return !!this._propertyPane && this._propertyPane.isOpen(instanceId);
};
/**
* Returns the state of the ContentPanel if it is open or not.
* Returns true if the Content Panel is open, regardless if the Content Panel is rendering the property pane.
*/
ClientSideWebPartManager.prototype.isContentPanelOpen = function () {
var _a, _b;
return !!((_b = (_a = this._propertyPane) === null || _a === void 0 ? void 0 : _a.isContentPanelOpen) === null || _b === void 0 ? void 0 : _b.call(_a));
};
/**
* Method to handle the web part delete action from the host. There is a key distinction between delete and dispose.
* Delete implies that the web part has been deleted from the page and the web part should dispose all the server
* side or other external resources attached to the web part. Dispose implies that an in-place navigation is
* happening and the web part manager should delete the web part from its cache.
*
* @param instanceId - instance id of the webpart which is deleted.
*/
ClientSideWebPartManager.prototype.onWebPartDelete = function (instanceId) {
var _a;
this.disposeWebparts(instanceId);
if ((0, Flights_1.isLoadEditModeWebPartsInParallelEnabled)() && instanceId) {
(_a = this.webPartPrefetching) === null || _a === void 0 ? void 0 : _a.cancelPrefetching(instanceId);
}
};
/**
* Render an error message in the web part container div. Also logs the error message to the IWebPartHost logger.
*/
ClientSideWebPartManager.prototype.renderError = function (domElement, error) {
var _this = this;
(0, ExecuteWithoutFailing_1.executeWithoutFailing)(function () {
_this._statusRenderer.renderError(domElement, error);
sp_diagnostics_1._TraceLogger.logErrorData({
source: ClientSideWebPartManager._logSource,
error: error,
serviceScope: _this._host.serviceScope
});
}, ClientSideWebPartManager._logSource);
};
/**
* Notify webparts that their container has resized.
*
* @param instanceId -