@atlaskit/editor-plugin-synced-block
Version:
SyncedBlock plugin for @atlaskit/editor-core
1,020 lines (1,001 loc) • 46.9 kB
JavaScript
/* 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)))));
};