UNPKG

@atlaskit/editor-plugin-synced-block

Version:

SyncedBlock plugin for @atlaskit/editor-core

1,020 lines (1,001 loc) • 46.9 kB
/* SyncedLocationDropdown.tsx generated by @compiled/babel-plugin v3.0.2 */ "use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.processReferenceData = exports.buildFieldAwareItems = exports.SyncedLocationDropdownWithCount = exports.SyncedLocationDropdown = void 0; require("./SyncedLocationDropdown.compiled.css"); var _react = _interopRequireWildcard(require("react")); var React = _react; var _runtime = require("@compiled/react/runtime"); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react2 = require("@compiled/react"); var _dropdownMenuItem = _interopRequireDefault(require("@atlaskit/dropdown-menu/dropdown-menu-item")); var _dropdownMenuItemGroup = _interopRequireDefault(require("@atlaskit/dropdown-menu/dropdown-menu-item-group")); var _analytics = require("@atlaskit/editor-common/analytics"); var _messages = require("@atlaskit/editor-common/messages"); var _syncBlock = require("@atlaskit/editor-common/sync-block"); var _ui = require("@atlaskit/editor-common/ui"); var _uiMenu = require("@atlaskit/editor-common/ui-menu"); var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider"); var _pageLiveDoc = _interopRequireDefault(require("@atlaskit/icon-lab/core/page-live-doc")); var _bug = _interopRequireDefault(require("@atlaskit/icon/core/bug")); var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-down")); var _epic = _interopRequireDefault(require("@atlaskit/icon/core/epic")); var _lockLocked = _interopRequireDefault(require("@atlaskit/icon/core/lock-locked")); var _page = _interopRequireDefault(require("@atlaskit/icon/core/page")); var _quotationMark = _interopRequireDefault(require("@atlaskit/icon/core/quotation-mark")); var _statusError = _interopRequireDefault(require("@atlaskit/icon/core/status-error")); var _story = _interopRequireDefault(require("@atlaskit/icon/core/story")); var _subtasks = _interopRequireDefault(require("@atlaskit/icon/core/subtasks")); var _task = _interopRequireDefault(require("@atlaskit/icon/core/task")); var _iconTile = _interopRequireDefault(require("@atlaskit/icon/icon-tile")); var _logo = require("@atlaskit/logo"); var _atlassianIcon = require("@atlaskit/logo/atlassian-icon"); var _lozenge = _interopRequireDefault(require("@atlaskit/lozenge/lozenge")); var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled"); var _compiled = require("@atlaskit/primitives/compiled"); var _spinner = _interopRequireDefault(require("@atlaskit/spinner/spinner")); var _Tooltip = _interopRequireDefault(require("@atlaskit/tooltip/Tooltip")); var _types = require("../types"); var _SyncedLocationsEmptyStateIllustration = require("./assets/SyncedLocationsEmptyStateIllustration"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } // eslint-disable-next-line import/order -- CI requires icon-lab imports before core icon imports. var fadeIn = null; var headingStyles = null; var dropdownItemStyles = null; // logo icon does not fit in ADS IconTile, hence we need custom styles to match with other icons var logoTileStyles = null; // Breadcrumbs and smart links draw the work item avatar without a tile. The 20px box keeps // Jira rows aligned with the tiled Confluence rows. var issueTypeAvatarStyles = null; var SYNCED_LOCATIONS_DROPDOWN_TEST_ID = 'synced-block-synced-locations-dropdown'; var styles = { title: "_1reo15vq _18m915vq _syazazsu _1bto1l2s _o5721q9c", note: "_syaz1rpy _o5721q9c", lozenge: "_ahbq12x7 _1ul91wqb", activationDropdownContent: "_1rjcze3t _1bsb1kdj", activationNoResultsContainer: "_vchhusvi _1bsb1kdj _ca0q1ejb _n3td1ejb", activationNoResultsContent: "_195g1wug _1bsb12aa _y3gn1h6o", fieldAwareDropdownContent: "_1bsb1kdj", fieldSecondLine: "_1reo15vq _18m915vq _o5721q9c _1bto1l2s", dropdownContent: "_1rjcv77o _1bsbsmdz _c71lko4j _1e0c1txw _1bah1h6o _4cvr1h6o", containerWithMinHeight: "_1tkeqkoa", contentContainer: "_y44vfmxe _1bsb1osq _1wpz1fhb _18m91wug", errorContainer: "_1bsbo8uj _1e0c1txw", errorIcon: "_1mour5cr", learnMoreLink: "_4bfu1r31 _1hmsglyw _ajmmnqa1", requestAccess: "_1bsb19n7 _o5721q9c _ahbq12x7 _syaz1rpy", restrictedIcon: "_1e0c1txw _4cvr1h6o _1wpz1h6o _ahbq1b66" }; var isRestrictedLocation = function isRestrictedLocation(reference) { return !reference.hasAccess && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_blocks_patch_11'); }; /** The user requests access on the location itself, so a restricted row only shows a lock. */ var NoAccessIndicator = function NoAccessIndicator(_ref) { var formatMessage = _ref.formatMessage; return (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_blocks_patch_11') ? /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.restrictedIcon }, /*#__PURE__*/React.createElement(_lockLocked.default, { label: "", size: "small", color: "var(--ds-icon-danger, #C9372C)" })) : /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.requestAccess }, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownRequestAccess)); }; /** * One field-aware dropdown row. Every string the row shows is composed here from the untouched * provider `reference`. Only built with `editor_synced_blocks_jira_custom_rich_text` on. */ /** Decided once per fetch. The control shape is what the dropdown held before the experiment. */ var EMPTY_LOCATIONS = { kind: 'control', references: [] }; var countLocations = function countLocations(locations) { return locations.kind === 'control' ? locations.references.length : locations.items.length; }; var shouldApplyMinHeight = function shouldApplyMinHeight(fetchStatus, itemCount) { // When there are 1/2 items, dropdown height is less than minHeight 144px return !(fetchStatus === 'success' && itemCount > 0); }; var ItemTitle = function ItemTitle(_ref2) { var title = _ref2.title, formatMessage = _ref2.formatMessage, onSameDocument = _ref2.onSameDocument, isSource = _ref2.isSource, hasAccess = _ref2.hasAccess, productType = _ref2.productType; return /*#__PURE__*/React.createElement(_compiled.Inline, null, /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.title }, title), onSameDocument && /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.note }, "\xA0-", ' ', formatMessage(productType === 'confluence-page' ? _messages.syncBlockMessages.syncedLocationDropdownTitleNoteForConfluencePage : _messages.syncBlockMessages.syncedLocationDropdownTitleNoteForJiraWorkItem)), isSource && /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.lozenge }, /*#__PURE__*/React.createElement(_lozenge.default, null, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownSourceLozenge))), !hasAccess && /*#__PURE__*/React.createElement(NoAccessIndicator, { formatMessage: formatMessage })); }; var productIconMap = { 'confluence-page': _logo.ConfluenceIcon, 'jira-work-item': _logo.JiraIcon }; var subTypeIconMap = { live: _pageLiveDoc.default, page: _page.default }; var getConfluenceSubTypeIcon = function getConfluenceSubTypeIcon(sourceAri, subType) { try { var _getPageIdAndTypeFrom = (0, _editorSyncedBlockProvider.getPageIdAndTypeFromConfluencePageAri)({ ari: sourceAri }), pageType = _getPageIdAndTypeFrom.type; if (pageType === 'blogpost') { return _quotationMark.default; } else { return subType && subType in subTypeIconMap ? subTypeIconMap[subType] : _page.default; } } catch (_unused) { return _page.default; } }; var ProductIcon = function ProductIcon(_ref3) { var _productIconMap$produ; var product = _ref3.product; var ProductIcon = product ? (_productIconMap$produ = productIconMap[product]) !== null && _productIconMap$produ !== void 0 ? _productIconMap$produ : _atlassianIcon.AtlassianIcon : _atlassianIcon.AtlassianIcon; return /*#__PURE__*/React.createElement("span", { className: (0, _runtime.ax)(["_2rkol0p1 _bfhki8nm _1bsbgktf _4t3igktf _1e0c1txw _4cvr1h6o _1bah1h6o"]) }, /*#__PURE__*/React.createElement(ProductIcon, { size: "xxsmall", appearance: "neutral" })); }; // Map AGG issue-type names to ADS icons. The mapping is by the English `name` returned // from AGG because Jira's REST/GraphQL API does not localise it at this layer. With // `platform_editor_blocks_patch_11` the AGG `iconUrl` wins and these icons are the fallback. // // Type the icons as the same shape as `TaskIcon` so we don't import `NewCoreIconProps` // from a private icon entrypoint. var jiraIssueTypeIconMap = { Task: { icon: _task.default, messageKey: 'syncedLocationDropdownIssueTypeTask' }, Bug: { icon: _bug.default, messageKey: 'syncedLocationDropdownIssueTypeBug' }, Story: { icon: _story.default, messageKey: 'syncedLocationDropdownIssueTypeStory' }, Epic: { icon: _epic.default, messageKey: 'syncedLocationDropdownIssueTypeEpic' }, Subtask: { icon: _subtasks.default, messageKey: 'syncedLocationDropdownIssueTypeSubtask' }, 'Sub-task': { icon: _subtasks.default, messageKey: 'syncedLocationDropdownIssueTypeSubtask' } }; /** * Creates an icon component from a custom Jira issue-type `iconUrl` that conforms to the * ADS icon component contract expected by `IconTile`. This lets us reuse `IconTile` for * custom issue types — ensuring consistent sizing, background, and border-radius with the * standard ADS icons used for known issue types (Bug, Story, etc.). * * The returned component ignores ADS icon props (color, spacing, etc.) because the image * is an external raster/SVG asset that doesn't respond to design tokens. */ var customIconCache = new Map(); var createCustomIssueTypeIcon = function createCustomIssueTypeIcon(iconUrl) { var cached = customIconCache.get(iconUrl); if (cached) { return cached; } var CustomIssueTypeIcon = function CustomIssueTypeIcon() { return /*#__PURE__*/React.createElement("img", { src: iconUrl, alt: "", width: "12", height: "12" }); }; CustomIssueTypeIcon.displayName = 'CustomIssueTypeIcon'; customIconCache.set(iconUrl, CustomIssueTypeIcon); return CustomIssueTypeIcon; }; /** * Returns the icon to render for a Jira issue type, or `null` when neither an ADS icon * mapping nor an AGG-provided `iconUrl` is available so the caller can fall back to a * generic product icon. * * Implemented as a plain function (not a React component) so the `null` check actually * narrows — a JSX expression always evaluates to a truthy `ReactElement` object, * meaning callers cannot distinguish a "would render nothing" component from one that * renders an icon. */ var renderJiraIssueTypeIcon = function renderJiraIssueTypeIcon(issueType, intl) { var mapped = jiraIssueTypeIconMap[issueType.name]; var label = intl.formatMessage(mapped ? _messages.syncBlockMessages[mapped.messageKey] : _messages.syncBlockMessages.syncedLocationDropdownIssueTypeGeneric); if (issueType.iconUrl && (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_blocks_patch_11')) { return /*#__PURE__*/React.createElement("span", { className: (0, _runtime.ax)(["_1bsbgktf _4t3igktf _1e0c1txw _1o9zidpf _4cvr1h6o _1bah1h6o"]) }, /*#__PURE__*/React.createElement("img", { src: issueType.iconUrl, alt: label, width: "16", height: "16" })); } if (mapped) { return /*#__PURE__*/React.createElement(_iconTile.default, { icon: mapped.icon, label: label, appearance: 'gray', size: "xsmall" }); } // Custom Jira issue types — render inside `IconTile` using a wrapper component so the // icon gets the same tile background, border-radius, and sizing as known issue types. if (issueType.iconUrl) { var CustomIcon = createCustomIssueTypeIcon(issueType.iconUrl); return /*#__PURE__*/React.createElement(_iconTile.default, { icon: CustomIcon, label: label, appearance: 'gray', size: "xsmall" }); } return null; }; var ItemIcon = function ItemIcon(_ref4) { var reference = _ref4.reference, intl = _ref4.intl; var hasAccess = reference.hasAccess, subType = reference.subType, productType = reference.productType, sourceAri = reference.sourceAri, issueType = reference.issueType; if (productType === 'confluence-page' && hasAccess) { return /*#__PURE__*/React.createElement(_iconTile.default, { icon: getConfluenceSubTypeIcon(sourceAri, subType), label: "", appearance: 'gray', size: "xsmall" }); } // Render a Jira issue-type icon when we have one. // Falls through to the generic product icon when: // - we don't have access (issueType is not surfaced for no-access references), // - AGG returned no `issueType` (partial index, deleted, etc.), or // - the issue type is unrecognised AND has no `iconUrl`. if (productType === 'jira-work-item' && hasAccess && issueType) { var icon = renderJiraIssueTypeIcon(issueType, intl); if (icon !== null) { return icon; } } // Generic product fallback for `jira-work-item` (and any future product). return /*#__PURE__*/React.createElement(ProductIcon, { product: productType }); }; var processReferenceData = exports.processReferenceData = function processReferenceData(referenceData, intl) { var formatMessage = intl.formatMessage; var sourceInfoMap = new Map(); referenceData === null || referenceData === void 0 || referenceData.forEach(function (reference) { if (!reference) { return; } if (sourceInfoMap.has(reference.sourceAri)) { var _sourceInfoMap$get; (_sourceInfoMap$get = sourceInfoMap.get(reference.sourceAri)) === null || _sourceInfoMap$get === void 0 || _sourceInfoMap$get.push(reference); } else { sourceInfoMap.set(reference.sourceAri, [reference]); } }); var _iterator = _createForOfIteratorHelper(sourceInfoMap.values()), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var references = _step.value; if (references.length > 1) { references.forEach(function (reference, index) { return reference.title = "".concat(reference.title === '' && reference.hasAccess ? formatMessage(_messages.syncBlockMessages.syncedLocationDropdownUntitledPage) : reference.title, ": ").concat(formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitleBlockIndex, { index: index + 1 })); }); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var sortedReferences = Array.from(sourceInfoMap.values()).flat().sort(function (a, b) { if (a.isSource !== b.isSource) { return b.isSource ? 1 : -1; } if (a.hasAccess !== b.hasAccess) { return a.hasAccess ? -1 : 1; } return (a.title || '').localeCompare(b.title || ''); }); return sortedReferences; }; var isFieldAwareLocationList = function isFieldAwareLocationList(references) { var _references$some; return ((_references$some = references === null || references === void 0 ? void 0 : references.some(function (reference) { return (reference === null || reference === void 0 ? void 0 : reference.productType) === 'jira-work-item'; })) !== null && _references$some !== void 0 ? _references$some : false) && (0, _isExperimentEnabled.isExperimentEnabled)('editor_synced_blocks_jira_custom_rich_text'); }; var groupBySourceAri = function groupBySourceAri(referenceData) { var groups = new Map(); referenceData === null || referenceData === void 0 || referenceData.forEach(function (reference) { if (!reference) { return; } var group = groups.get(reference.sourceAri); if (group) { group.push(reference); } else { groups.set(reference.sourceAri, [reference]); } }); return groups; }; /** Sources first, then accessible locations. `0` leaves the title order to the caller. */ var compareLocationOrder = function compareLocationOrder(a, b) { if (a.isSource !== b.isSource) { return b.isSource ? 1 : -1; } if (a.hasAccess !== b.hasAccess) { return a.hasAccess ? -1 : 1; } return 0; }; /** The title alone. The field name is placed by the row and the tooltip, not baked in here. */ var getBaseTitle = function getBaseTitle(_ref5) { var blockIndex = _ref5.blockIndex, formatMessage = _ref5.formatMessage, reference = _ref5.reference; if (isRestrictedLocation(reference)) { return formatMessage(_messages.syncBlockMessages.syncedLocationDropdownRestrictedContent); } var title = reference.title === '' && reference.hasAccess ? formatMessage(_messages.syncBlockMessages.syncedLocationDropdownUntitledPage) : reference.title || reference.url || ''; return blockIndex === undefined ? title : "".concat(title, ": ").concat(formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitleBlockIndex, { index: blockIndex })); }; /** Jira rows are noted from `locationScope`; other rows keep the pre-experiment `onSameDocument` note. */ var getFieldAwareNote = function getFieldAwareNote(reference, formatMessage) { var _reference$locationSc; if (reference.productType !== 'jira-work-item') { if (!reference.onSameDocument) { return undefined; } return formatMessage(reference.productType === 'confluence-page' ? _messages.syncBlockMessages.syncedLocationDropdownTitleNoteForConfluencePage : _messages.syncBlockMessages.syncedLocationDropdownTitleNoteForJiraWorkItem); } // A provider that computes no scope still reports `onSameDocument`. It is the same host // comparison `getLocationScope` starts with, and in Jira the host document is one field. var locationScope = (_reference$locationSc = reference.locationScope) !== null && _reference$locationSc !== void 0 ? _reference$locationSc : reference.onSameDocument ? 'same-document' : undefined; switch (locationScope) { case 'same-document': return formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitleNoteForJiraWorkItemField); case 'same-parent-document': return formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitleNoteForJiraWorkItem); default: return undefined; } }; var buildFieldAwareItems = exports.buildFieldAwareItems = function buildFieldAwareItems(referenceData, formatMessage) { return Array.from(groupBySourceAri(referenceData).values()).flatMap(function (group) { return group.map(function (reference, index) { var fieldName = reference.productType === 'jira-work-item' ? reference.fieldName : undefined; var note = getFieldAwareNote(reference, formatMessage); return _objectSpread(_objectSpread(_objectSpread({ baseTitle: getBaseTitle({ blockIndex: group.length > 1 ? index + 1 : undefined, formatMessage: formatMessage, reference: reference }) }, fieldName !== undefined && { fieldName: fieldName }), {}, { key: "".concat(reference.sourceAri, "#").concat(index) }, note !== undefined && { note: note }), {}, { reference: reference }); }); }).sort(function (a, b) { return compareLocationOrder(a.reference, b.reference) || a.baseTitle.localeCompare(b.baseTitle); }); }; var toSyncedLocations = function toSyncedLocations(references, intl) { return isFieldAwareLocationList(references) ? { kind: 'field-aware', items: buildFieldAwareItems(references, intl.formatMessage) } : { kind: 'control', references: processReferenceData(references, intl) }; }; var SyncedLocationDropdown = exports.SyncedLocationDropdown = function SyncedLocationDropdown(_ref6) { var syncBlockStore = _ref6.syncBlockStore, resourceId = _ref6.resourceId, intl = _ref6.intl, isSource = _ref6.isSource, localId = _ref6.localId, api = _ref6.api, floatingToolbarRenderContext = _ref6.floatingToolbarRenderContext; return /*#__PURE__*/React.createElement(EditorPositionedSyncedLocationDropdown, { syncBlockStore: syncBlockStore, resourceId: resourceId, intl: intl, isSource: isSource, localId: localId, api: api, floatingToolbarRenderContext: floatingToolbarRenderContext }); }; var EditorPositionedSyncedLocationDropdown = function EditorPositionedSyncedLocationDropdown(_ref7) { var syncBlockStore = _ref7.syncBlockStore, resourceId = _ref7.resourceId, intl = _ref7.intl, isSource = _ref7.isSource, localId = _ref7.localId, api = _ref7.api, floatingToolbarRenderContext = _ref7.floatingToolbarRenderContext; var triggerTitle = intl.formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitle); var _useState = (0, _react.useState)(false), _useState2 = (0, _slicedToArray2.default)(_useState, 2), isOpen = _useState2[0], setIsOpen = _useState2[1]; var content = isOpen ? /*#__PURE__*/React.createElement(DropdownContent, { syncBlockStore: syncBlockStore, resourceId: resourceId, intl: intl, isSource: isSource, localId: localId, api: api }) : null; var toggleOpen = (0, _react.useCallback)(function () { setIsOpen(function (currentIsOpen) { return !currentIsOpen; }); }, []); var closeDropdown = (0, _react.useCallback)(function () { setIsOpen(false); }, []); var setDisableParentScroll = floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.setDisableParentScroll; (0, _react.useEffect)(function () { if (!isOpen) { return; } setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(true); return function () { setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(false); }; }, [isOpen, setDisableParentScroll]); var trigger = (0, _react.useMemo)(function () { return /*#__PURE__*/React.createElement(_ui.FloatingToolbarButton, { areAnyNewToolbarFlagsEnabled: true, testId: _types.SYNCED_BLOCK_BUTTON_TEST_ID.syncedBlockToolbarSyncedLocationsTrigger, selected: isOpen, iconAfter: /*#__PURE__*/React.createElement(_chevronDown.default, { color: "currentColor", spacing: "spacious", label: "", size: "small" }), onClick: toggleOpen, ariaHasPopup: true }, triggerTitle); }, [isOpen, toggleOpen, triggerTitle]); return /*#__PURE__*/React.createElement(_uiMenu.DropdownContainer, { testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID, isOpen: isOpen, trigger: trigger, handleClickOutside: closeDropdown, handleEscapeKeydown: closeDropdown, mountTo: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsMountPoint, boundariesElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsBoundariesElement, scrollableElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsScrollableElement // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , arrowKeyNavigationProviderOptions: { type: _uiMenu.ArrowKeyNavigationType.MENU } }, content); }; var SyncedLocationDropdownWithCount = exports.SyncedLocationDropdownWithCount = function SyncedLocationDropdownWithCount(_ref8) { var syncBlockStore = _ref8.syncBlockStore, resourceId = _ref8.resourceId, intl = _ref8.intl, isSource = _ref8.isSource, localId = _ref8.localId, api = _ref8.api, floatingToolbarRenderContext = _ref8.floatingToolbarRenderContext; var _useState3 = (0, _react.useState)(false), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), isOpen = _useState4[0], setIsOpen = _useState4[1]; var _useReferenceData = useReferenceData({ intl: intl, isSource: isSource, localId: localId, resourceId: resourceId, syncBlockStore: syncBlockStore }), fetchStatus = _useReferenceData.fetchStatus, locations = _useReferenceData.locations; var referenceCount = (0, _react.useMemo)(function () { switch (locations.kind) { case 'control': return locations.references.filter(function (_ref9) { var isSourceItem = _ref9.isSource; return !isSourceItem; }).length; case 'field-aware': return locations.items.filter(function (_ref0) { var reference = _ref0.reference; return !reference.isSource; }).length; } }, [locations]); var tooltipContent = !isOpen && fetchStatus === 'success' && referenceCount === 0 ? intl.formatMessage(_messages.syncBlockMessages.syncedLocationDropdownNoReferencesTooltip) : null; var content = isOpen ? /*#__PURE__*/React.createElement(DropdownContentWithReferenceData, { resourceId: resourceId, intl: intl, api: api, fetchStatus: fetchStatus, locations: locations }) : null; var toggleOpen = (0, _react.useCallback)(function () { setIsOpen(function (currentIsOpen) { return !currentIsOpen; }); }, []); var closeDropdown = (0, _react.useCallback)(function () { setIsOpen(false); }, []); var setDisableParentScroll = floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.setDisableParentScroll; (0, _react.useEffect)(function () { if (!isOpen) { return; } setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(true); return function () { setDisableParentScroll === null || setDisableParentScroll === void 0 || setDisableParentScroll(false); }; }, [isOpen, setDisableParentScroll]); var trigger = (0, _react.useMemo)(function () { return /*#__PURE__*/React.createElement(_ui.FloatingToolbarButton, { areAnyNewToolbarFlagsEnabled: true, testId: _types.SYNCED_BLOCK_BUTTON_TEST_ID.syncedBlockToolbarSyncedLocationsTrigger, selected: isOpen, iconAfter: /*#__PURE__*/React.createElement(_chevronDown.default, { color: "currentColor", spacing: "spacious", label: "", size: "small" }), onClick: toggleOpen, ariaHasPopup: true, tooltipContent: tooltipContent !== null && tooltipContent !== void 0 ? tooltipContent : undefined }, /*#__PURE__*/React.createElement(SyncedLocationTriggerContent, { intl: intl, fetchStatus: fetchStatus, referenceCount: referenceCount })); }, [fetchStatus, intl, isOpen, referenceCount, toggleOpen, tooltipContent]); return /*#__PURE__*/React.createElement(_uiMenu.DropdownContainer, { alignDropdownWithParentElement: true, alignX: "left", testId: SYNCED_LOCATIONS_DROPDOWN_TEST_ID, isOpen: isOpen, trigger: trigger, handleClickOutside: closeDropdown, handleEscapeKeydown: closeDropdown, mountTo: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsMountPoint, boundariesElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsBoundariesElement, scrollableElement: floatingToolbarRenderContext === null || floatingToolbarRenderContext === void 0 ? void 0 : floatingToolbarRenderContext.popupsScrollableElement // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , arrowKeyNavigationProviderOptions: { type: _uiMenu.ArrowKeyNavigationType.MENU } }, content); }; var DropdownContent = function DropdownContent(_ref1) { var syncBlockStore = _ref1.syncBlockStore, resourceId = _ref1.resourceId, intl = _ref1.intl, isSource = _ref1.isSource, localId = _ref1.localId, api = _ref1.api; var _useState5 = (0, _react.useState)('none'), _useState6 = (0, _slicedToArray2.default)(_useState5, 2), fetchStatus = _useState6[0], setFetchStatus = _useState6[1]; var _useState7 = (0, _react.useState)(EMPTY_LOCATIONS), _useState8 = (0, _slicedToArray2.default)(_useState7, 2), locations = _useState8[0], setLocations = _useState8[1]; (0, _react.useEffect)(function () { setFetchStatus('loading'); var getReferenceData = /*#__PURE__*/function () { var _ref10 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() { var response; return _regenerator.default.wrap(function (_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.next = 1; return syncBlockStore.fetchReferencesSourceInfo(resourceId, localId, isSource); case 1: response = _context.sent; if (!response.error) { _context.next = 2; break; } setFetchStatus('error'); return _context.abrupt("return"); case 2: setLocations(toSyncedLocations(response.references, intl)); setFetchStatus('success'); case 3: case "end": return _context.stop(); } }, _callee); })); return function getReferenceData() { return _ref10.apply(this, arguments); }; }(); void getReferenceData(); }, [syncBlockStore, intl, isSource, localId, resourceId]); return /*#__PURE__*/React.createElement(DropdownContentWithReferenceData, { resourceId: resourceId, intl: intl, api: api, fetchStatus: fetchStatus, locations: locations }); }; var useReferenceData = function useReferenceData(_ref11) { var syncBlockStore = _ref11.syncBlockStore, resourceId = _ref11.resourceId, intl = _ref11.intl, isSource = _ref11.isSource, localId = _ref11.localId; var _useState9 = (0, _react.useState)(function () { return isSource && syncBlockStore.sourceManager.isNewSourceBlock(resourceId); }), _useState0 = (0, _slicedToArray2.default)(_useState9, 1), isNewSourceBlock = _useState0[0]; var _useState1 = (0, _react.useState)(function () { return { fetchStatus: isNewSourceBlock ? 'success' : 'loading', locations: EMPTY_LOCATIONS }; }), _useState10 = (0, _slicedToArray2.default)(_useState1, 2), state = _useState10[0], setState = _useState10[1]; (0, _react.useEffect)(function () { var isCurrentRequest = true; setState({ fetchStatus: isNewSourceBlock ? 'success' : 'loading', locations: EMPTY_LOCATIONS }); var getReferenceData = /*#__PURE__*/function () { var _ref12 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() { var response; return _regenerator.default.wrap(function (_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: _context2.next = 1; return syncBlockStore.fetchReferencesSourceInfo(resourceId, localId, isSource); case 1: response = _context2.sent; if (isCurrentRequest) { _context2.next = 2; break; } return _context2.abrupt("return"); case 2: if (isNewSourceBlock) { syncBlockStore.sourceManager.clearNewSourceBlock(resourceId); } if (!response.error) { _context2.next = 3; break; } setState({ fetchStatus: 'error', locations: EMPTY_LOCATIONS }); return _context2.abrupt("return"); case 3: setState({ fetchStatus: 'success', locations: toSyncedLocations(response.references, intl) }); case 4: case "end": return _context2.stop(); } }, _callee2); })); return function getReferenceData() { return _ref12.apply(this, arguments); }; }(); void getReferenceData(); return function () { isCurrentRequest = false; }; }, [syncBlockStore, resourceId, intl, isSource, localId, isNewSourceBlock]); return { fetchStatus: state.fetchStatus, locations: state.locations }; }; var SyncedLocationTriggerContent = function SyncedLocationTriggerContent(_ref13) { var intl = _ref13.intl, fetchStatus = _ref13.fetchStatus, referenceCount = _ref13.referenceCount; var formatMessage = intl.formatMessage; var triggerTitle = formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitle); var syncedLocationCount = referenceCount === 0 ? 0 : referenceCount + 1; switch (fetchStatus) { case 'loading': return /*#__PURE__*/React.createElement(_compiled.Inline, { alignBlock: "center", space: "space.050" }, triggerTitle, /*#__PURE__*/React.createElement(_spinner.default, { size: "small", label: formatMessage(_messages.syncBlockMessages.syncedLocationDropdownLoading) })); case 'success': { var count = syncedLocationCount > 99 ? '99+' : intl.formatNumber(syncedLocationCount); return formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTitleWithCount, { count: count }); } case 'none': case 'error': return triggerTitle; } }; var DropdownContentWithReferenceData = function DropdownContentWithReferenceData(_ref14) { var resourceId = _ref14.resourceId, intl = _ref14.intl, api = _ref14.api, fetchStatus = _ref14.fetchStatus, locations = _ref14.locations; var formatMessage = intl.formatMessage; var locationCount = countLocations(locations); var handleLocationClick = function handleLocationClick() { var _api$analytics; api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.fireAnalyticsEvent({ eventType: _analytics.EVENT_TYPE.OPERATIONAL, action: _analytics.ACTION.CLICKED, actionSubject: _analytics.ACTION_SUBJECT.SYNCED_BLOCK, actionSubjectId: _analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_CLICK_SYNCED_LOCATION, attributes: { resourceId: resourceId } }); }; var content = function content() { switch (fetchStatus) { case 'loading': return /*#__PURE__*/React.createElement(LoadingScreen, { formatMessage: formatMessage }); case 'error': return /*#__PURE__*/React.createElement(ErrorScreen, { formatMessage: formatMessage }); case 'success': if (locationCount > 0) { return /*#__PURE__*/React.createElement("div", { "data-testid": "synced-locations-dropdown-content", className: (0, _runtime.ax)([styles.contentContainer, "_ku9g126e _18bk1rpy"]) }, /*#__PURE__*/React.createElement(_dropdownMenuItemGroup.default, { title: formatMessage(_messages.syncBlockMessages.syncedLocationDropdownHeading, { count: "".concat(locationCount > 99 ? '99+' : locationCount) }) }, locations.kind === 'field-aware' ? /*#__PURE__*/React.createElement(FieldAwareLocationRows, { items: locations.items, intl: intl, handleLocationClick: handleLocationClick }) : /*#__PURE__*/React.createElement(ControlLocationRows, { referenceData: locations.references, intl: intl, handleLocationClick: handleLocationClick }))); } else { return /*#__PURE__*/React.createElement(NoResultScreen, { formatMessage: formatMessage }); } } }; return /*#__PURE__*/React.createElement(_compiled.Box, { xcss: (0, _react2.cx)(styles.dropdownContent, locations.kind === 'field-aware' && styles.fieldAwareDropdownContent, fetchStatus === 'success' && locationCount === 0 && styles.activationDropdownContent, shouldApplyMinHeight(fetchStatus, locationCount) && styles.containerWithMinHeight) }, content()); }; // The pre-experiment rows. This block is master's, moved into a component; remove with the experiment. var ControlLocationRows = function ControlLocationRows(_ref15) { var referenceData = _ref15.referenceData, intl = _ref15.intl, handleLocationClick = _ref15.handleLocationClick; var formatMessage = intl.formatMessage; return /*#__PURE__*/React.createElement(_react.Fragment, null, referenceData.map(function (reference, index) { var title = isRestrictedLocation(reference) ? formatMessage(_messages.syncBlockMessages.syncedLocationDropdownRestrictedContent) : reference.title === '' && reference.hasAccess ? formatMessage(_messages.syncBlockMessages.syncedLocationDropdownUntitledPage) : reference.title || reference.url || ''; return /*#__PURE__*/React.createElement("div", { key: (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_blocks_patch_11') ? "".concat(reference.sourceAri, "#").concat(index) : reference.title, className: (0, _runtime.ax)(["_2ll012x7"]) }, /*#__PURE__*/React.createElement(_Tooltip.default, { content: title }, /*#__PURE__*/React.createElement(_dropdownMenuItem.default, { elemBefore: /*#__PURE__*/React.createElement(ItemIcon, { reference: reference, intl: intl }), href: reference.url, target: "_blank", key: reference.title, rel: "noopener noreferrer" // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClick: function onClick() { return handleLocationClick(); } }, /*#__PURE__*/React.createElement(ItemTitle, { title: title, formatMessage: formatMessage, onSameDocument: reference.onSameDocument, isSource: reference.isSource, hasAccess: reference.hasAccess, productType: reference.productType })))); })); }; var FieldAwareItemTitle = function FieldAwareItemTitle(_ref16) { var _ref16$item = _ref16.item, baseTitle = _ref16$item.baseTitle, fieldName = _ref16$item.fieldName, note = _ref16$item.note, reference = _ref16$item.reference, formatMessage = _ref16.formatMessage; var titleLine = /*#__PURE__*/React.createElement(_compiled.Inline, null, /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.title }, baseTitle), note && /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.note }, "\xA0- ", note), reference.isSource && /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.lozenge }, /*#__PURE__*/React.createElement(_lozenge.default, null, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownSourceLozenge))), !reference.hasAccess && /*#__PURE__*/React.createElement(NoAccessIndicator, { formatMessage: formatMessage })); if (fieldName === undefined) { return titleLine; } // AGG localises the field name, so it is shown as given rather than wrapped in a message. return /*#__PURE__*/React.createElement(_compiled.Stack, null, titleLine, /*#__PURE__*/React.createElement(_compiled.Box, { as: "span", xcss: styles.fieldSecondLine }, /*#__PURE__*/React.createElement(_compiled.Text, { size: "small", color: "color.text.subtlest" }, fieldName))); }; var FieldAwareLocationRows = function FieldAwareLocationRows(_ref17) { var items = _ref17.items, intl = _ref17.intl, handleLocationClick = _ref17.handleLocationClick; var formatMessage = intl.formatMessage; return /*#__PURE__*/React.createElement(_react.Fragment, null, items.map(function (item) { return /*#__PURE__*/React.createElement("div", { key: item.key, className: (0, _runtime.ax)(["_2ll012x7"]) }, /*#__PURE__*/React.createElement(_Tooltip.default, { content: item.fieldName ? /*#__PURE__*/ // Two lines in the tooltip's own text flow. Wrapping them in `Text` would // default to `font.body` and override the container's `font.body.small`, // so the field-aware tooltip would not match every other one. React.createElement(_react.Fragment, null, item.baseTitle, /*#__PURE__*/React.createElement("br", null), formatMessage(_messages.syncBlockMessages.syncedLocationDropdownTooltipFieldName, { fieldName: item.fieldName })) : item.baseTitle }, /*#__PURE__*/React.createElement(_dropdownMenuItem.default, { elemBefore: /*#__PURE__*/React.createElement(ItemIcon, { reference: item.reference, intl: intl }), href: item.reference.url, target: "_blank", rel: "noopener noreferrer" // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClick: function onClick() { return handleLocationClick(); } }, /*#__PURE__*/React.createElement(FieldAwareItemTitle, { item: item, formatMessage: formatMessage })))); })); }; var LoadingScreen = function LoadingScreen(_ref18) { var formatMessage = _ref18.formatMessage; return /*#__PURE__*/React.createElement(_compiled.Box, null, /*#__PURE__*/React.createElement(_spinner.default, { label: formatMessage(_messages.syncBlockMessages.syncedLocationDropdownLoading) })); }; var ErrorScreen = function ErrorScreen(_ref19) { var formatMessage = _ref19.formatMessage; return /*#__PURE__*/React.createElement(_compiled.Box, { xcss: styles.errorContainer, testId: "synced-locations-dropdown-content-error" }, /*#__PURE__*/React.createElement(_compiled.Box, { xcss: styles.errorIcon }, /*#__PURE__*/React.createElement(_statusError.default, { color: "var(--ds-icon-danger, #C9372C)", spacing: "spacious", label: "", size: "small" })), /*#__PURE__*/React.createElement(_compiled.Text, { as: "p", size: "medium" }, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownError))); }; var NoResultScreen = function NoResultScreen(_ref20) { var formatMessage = _ref20.formatMessage; return /*#__PURE__*/React.createElement(_compiled.Box, { xcss: styles.activationNoResultsContainer, testId: "synced-locations-dropdown-content-no-results" }, /*#__PURE__*/React.createElement(_compiled.Stack, { alignInline: "center", xcss: styles.activationNoResultsContent, space: "space.150" }, /*#__PURE__*/React.createElement(_SyncedLocationsEmptyStateIllustration.SyncedLocationsEmptyStateIllustration, null), /*#__PURE__*/React.createElement(_compiled.Text, { as: "p" }, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownActivationNoResults)), /*#__PURE__*/React.createElement(_compiled.Text, { as: "p" }, /*#__PURE__*/React.createElement(_compiled.Anchor, { href: _syncBlock.SYNCED_BLOCKS_DOCUMENTATION_URL, target: "_blank", rel: "noopener noreferrer", xcss: styles.learnMoreLink }, formatMessage(_messages.syncBlockMessages.syncedLocationDropdownLearnMoreLink))))); };