"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useNormalizedAppLinks = exports.useLinkInfo = exports.useLinkExists = exports.useLinkAuthorized = exports.useAppLinks = exports.updateAppLinks = exports.needsUrlState = exports.getLinksWithHiddenTimeline = exports.getLinkInfo = exports.getAncestorLinksInfo = exports.appLinks$ = void 0; var _react = require("react"); var _useObservable = _interopRequireDefault(require("react-use/lib/useObservable")); var _rxjs = require("rxjs"); var _capabilities = require("../lib/capabilities"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ /** * App links updater, it stores the links recursive hierarchy and keeps * the value of the app links in sync with all application components. * It can be updated using `updateAppLinks`. */ const appLinksUpdater$ = new _rxjs.BehaviorSubject([]); const appLinks$ = appLinksUpdater$.asObservable(); // stores a flatten normalized appLinkItems object for internal direct id access exports.appLinks$ = appLinks$; const normalizedAppLinksUpdater$ = new _rxjs.BehaviorSubject({}); /** * Updates the internal app links applying the filter by permissions */ const updateAppLinks = (appLinksToUpdate, linksPermissions) => { const processedAppLinks = processAppLinks(appLinksToUpdate, linksPermissions); appLinksUpdater$.next(Object.freeze(processedAppLinks)); normalizedAppLinksUpdater$.next(Object.freeze(getNormalizedLinks(processedAppLinks))); }; /** * Hook to get the app links updated value */ exports.updateAppLinks = updateAppLinks; const useAppLinks = () => (0, _useObservable.default)(appLinksUpdater$, appLinksUpdater$.getValue()); /** * Hook to get the normalized app links updated value */ exports.useAppLinks = useAppLinks; const useNormalizedAppLinks = () => (0, _useObservable.default)(normalizedAppLinksUpdater$, normalizedAppLinksUpdater$.getValue()); /** * Hook to check if a link exists in the application links, * It can be used to know if a link access is authorized. */ exports.useNormalizedAppLinks = useNormalizedAppLinks; const useLinkExists = id => { const normalizedLinks = useNormalizedAppLinks(); return (0, _react.useMemo)(() => !!normalizedLinks[id], [normalizedLinks, id]); }; exports.useLinkExists = useLinkExists; const useLinkInfo = id => { const normalizedLinks = useNormalizedAppLinks(); return (0, _react.useMemo)(() => { const normalizedLink = normalizedLinks[id]; if (!normalizedLink) { return undefined; } // discards the parentId and creates the linkInfo copy. const { parentId, ...linkInfo } = normalizedLink; return linkInfo; }, [normalizedLinks, id]); }; /** * Hook to check if a link exists in the application links, * It can be used to know if a link access is authorized. */ exports.useLinkInfo = useLinkInfo; const useLinkAuthorized = id => { const linkInfo = useLinkInfo(id); return (0, _react.useMemo)(() => linkInfo != null && !linkInfo.unauthorized, [linkInfo]); }; /** * Returns the `LinkInfo` from a link id parameter */ exports.useLinkAuthorized = useLinkAuthorized; const getLinkInfo = id => { const normalizedLink = getNormalizedLink(id); if (!normalizedLink) { return undefined; } // discards the parentId and creates the linkInfo copy. const { parentId, ...linkInfo } = normalizedLink; return linkInfo; }; /** * Returns the `LinkInfo` of all the ancestors to the parameter id link, also included. */ exports.getLinkInfo = getLinkInfo; const getAncestorLinksInfo = id => { const ancestors = []; let currentId = id; while (currentId) { const normalizedLink = getNormalizedLink(currentId); if (normalizedLink) { const { parentId, ...linkInfo } = normalizedLink; ancestors.push(linkInfo); currentId = parentId; } else { currentId = undefined; } } return ancestors.reverse(); }; /** * Returns `true` if the links needs to carry the application state in the url. * Defaults to `true` if the `skipUrlState` property of the `LinkItem` is `undefined`. */ exports.getAncestorLinksInfo = getAncestorLinksInfo; const needsUrlState = id => { var _getNormalizedLink; return !((_getNormalizedLink = getNormalizedLink(id)) !== null && _getNormalizedLink !== void 0 && _getNormalizedLink.skipUrlState); }; exports.needsUrlState = needsUrlState; const getLinksWithHiddenTimeline = () => { return Object.values(normalizedAppLinksUpdater$.getValue()).filter(link => link.hideTimeline); }; // Internal functions /** * Creates the `NormalizedLinks` structure from a `LinkItem` array */ exports.getLinksWithHiddenTimeline = getLinksWithHiddenTimeline; function getNormalizedLinks(currentLinks, parentId) { return currentLinks.reduce((normalized, { links, ...currentLink }) => { normalized[currentLink.id] = { ...currentLink, parentId }; if (links && links.length > 0) { Object.assign(normalized, getNormalizedLinks(links, currentLink.id)); } return normalized; }, {}); } const getNormalizedLink = id => normalizedAppLinksUpdater$.getValue()[id]; const processAppLinks = (appLinks, linksPermissions) => appLinks.reduce((acc, { links, ...appLinkWithoutSublinks }) => { if (!isLinkExperimentalKeyAllowed(appLinkWithoutSublinks, linksPermissions)) { return acc; } if (!(0, _capabilities.hasCapabilities)(linksPermissions.capabilities, appLinkWithoutSublinks.capabilities) || !isLinkLicenseAllowed(appLinkWithoutSublinks, linksPermissions)) { if (linksPermissions.upselling.isPageUpsellable(appLinkWithoutSublinks.id)) { acc.push({ ...appLinkWithoutSublinks, unauthorized: true }); } return acc; // not adding sub-links for links that are not authorized } const resultAppLink = appLinkWithoutSublinks; if (links) { const childrenLinks = processAppLinks(links, linksPermissions); if (childrenLinks.length > 0) { resultAppLink.links = childrenLinks; } } acc.push(resultAppLink); return acc; }, []); const isLinkExperimentalKeyAllowed = (link, { experimentalFeatures }) => { if (link.hideWhenExperimentalKey && experimentalFeatures[link.hideWhenExperimentalKey]) { return false; } if (link.experimentalKey && !experimentalFeatures[link.experimentalKey]) { return false; } return true; }; const isLinkLicenseAllowed = (link, { license }) => { var _link$licenseType; const linkLicenseType = (_link$licenseType = link.licenseType) !== null && _link$licenseType !== void 0 ? _link$licenseType : 'basic'; if (license) { if (!license.hasAtLeast(linkLicenseType)) { return false; } } else if (linkLicenseType !== 'basic') { return false; } return true; };