UNPKG

@atlaskit/mention

Version:

A React component used to display user profiles in a list for 'Mention' functionality

470 lines (462 loc) 17.5 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/inherits"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; 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) { _defineProperty(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; } import _regeneratorRuntime from "@babel/runtime/regenerator"; function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } import { utils as serviceUtils } from '@atlaskit/util-service-support'; import { isAppMention, isTeamMention, MentionNameStatus, SliNames, Actions } from '../types'; import debug from '../util/logger'; var MAX_QUERY_ITEMS = 100; var MAX_NOTIFIED_ITEMS = 20; // Re-exporting types to prevent breaking change // Re-exporting types to prevent breaking change import { SLI_EVENT_TYPE } from '../util/analytics'; import debounce from 'lodash/debounce'; /** * Support */ var emptySecurityProvider = function emptySecurityProvider() { return { params: {}, headers: {} }; }; var AbstractResource = /*#__PURE__*/function () { function AbstractResource() { _classCallCheck(this, AbstractResource); this.changeListeners = new Map(); this.allResultsListeners = new Map(); this.errListeners = new Map(); this.infoListeners = new Map(); this.analyticsListeners = new Map(); } return _createClass(AbstractResource, [{ key: "subscribe", value: function subscribe(key, callback, errCallback, infoCallback, allResultsCallback, analyticsListeners) { if (callback) { this.changeListeners.set(key, callback); } if (errCallback) { this.errListeners.set(key, errCallback); } if (infoCallback) { this.infoListeners.set(key, infoCallback); } if (allResultsCallback) { this.allResultsListeners.set(key, allResultsCallback); } if (analyticsListeners) { this.analyticsListeners.set(key, analyticsListeners); } } }, { key: "unsubscribe", value: function unsubscribe(key) { this.changeListeners.delete(key); this.errListeners.delete(key); this.infoListeners.delete(key); this.allResultsListeners.delete(key); this.analyticsListeners.delete(key); } }]); }(); var AbstractMentionResource = /*#__PURE__*/function (_ref) { function AbstractMentionResource() { _classCallCheck(this, AbstractMentionResource); return _callSuper(this, AbstractMentionResource, arguments); } _inherits(AbstractMentionResource, _ref); return _createClass(AbstractMentionResource, [{ key: "shouldHighlightMention", value: function shouldHighlightMention(_mention) { return false; } // eslint-disable-next-line class-methods-use-this }, { key: "filter", value: function filter(query) { throw new Error("not yet implemented.\nParams: query=".concat(query)); } // eslint-disable-next-line class-methods-use-this, no-unused-vars }, { key: "recordMentionSelection", value: function recordMentionSelection(_mention) { // Do nothing } }, { key: "isFiltering", value: function isFiltering(_query) { return false; } }, { key: "_notifyListeners", value: function _notifyListeners(mentionsResult, stats) { debug('ak-mention-resource._notifyListeners', mentionsResult && mentionsResult.mentions && mentionsResult.mentions.length, this.changeListeners); this.changeListeners.forEach(function (listener, key) { try { listener(mentionsResult.mentions.slice(0, MAX_NOTIFIED_ITEMS), mentionsResult.query, stats); } catch (e) { // ignore error from listener debug("error from listener '".concat(key, "', ignoring"), e); } }); } }, { key: "_notifyAllResultsListeners", value: function _notifyAllResultsListeners(mentionsResult) { debug('ak-mention-resource._notifyAllResultsListeners', mentionsResult && mentionsResult.mentions && mentionsResult.mentions.length, this.changeListeners); this.allResultsListeners.forEach(function (listener, key) { try { listener(mentionsResult.mentions.slice(0, MAX_NOTIFIED_ITEMS), mentionsResult.query); } catch (e) { // ignore error from listener debug("error from listener '".concat(key, "', ignoring"), e); } }); } }, { key: "_notifyErrorListeners", value: function _notifyErrorListeners(error, query) { this.errListeners.forEach(function (listener, key) { try { listener(error, query); } catch (e) { // ignore error from listener debug("error from listener '".concat(key, "', ignoring"), e); } }); } }, { key: "_notifyInfoListeners", value: function _notifyInfoListeners(info) { this.infoListeners.forEach(function (listener, key) { try { listener(info); } catch (e) { // ignore error fromr listener debug("error from listener '".concat(key, "', ignoring"), e); } }); } }, { key: "_notifyAnalyticsListeners", value: function _notifyAnalyticsListeners(event, actionSubject, action, attributes) { this.analyticsListeners.forEach(function (listener, key) { try { listener(event, actionSubject, action, attributes); } catch (e) { // ignore error from listener debug("error from listener '".concat(key, "', ignoring"), e); } }); } }]); }(AbstractResource); /** * Provides a Javascript API */ export var MentionResource = /*#__PURE__*/function (_AbstractMentionResou) { function MentionResource(config) { var _this; _classCallCheck(this, MentionResource); _this = _callSuper(this, MentionResource); _this.verifyMentionConfig(config); _this.config = config; _this.lastReturnedSearch = 0; _this.activeSearches = new Set(); _this.productName = config.productName; _this.shouldEnableInvite = !!config.shouldEnableInvite; _this.onInviteItemClick = config.onInviteItemClick; _this.inviteXProductUser = config.inviteXProductUser; _this.userRole = config.userRole || 'basic'; if (_this.config.debounceTime) { _this.filter = debounce(_this.filter, _this.config.debounceTime); } return _this; } _inherits(MentionResource, _AbstractMentionResou); return _createClass(MentionResource, [{ key: "shouldHighlightMention", value: function shouldHighlightMention(mention) { if (this.config.shouldHighlightMention) { return this.config.shouldHighlightMention(mention); } return false; } }, { key: "notify", value: function notify(searchTime, mentionResult, query) { if (searchTime > this.lastReturnedSearch) { this.lastReturnedSearch = searchTime; this._notifyListeners(mentionResult, { duration: Date.now() - searchTime }); } else { var date = new Date(searchTime).toISOString().substr(17, 6); debug('Stale search result, skipping', date, query); // eslint-disable-line no-console, max-len } this._notifyAllResultsListeners(mentionResult); } }, { key: "notifyError", value: function notifyError(error, query) { this._notifyErrorListeners(error, query); if (query) { this.activeSearches.delete(query); } } }, { key: "filter", value: function () { var _filter = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(query, contextIdentifier) { var searchTime, results, searchResponse; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.prev = 0; searchTime = Date.now(); if (query) { _context.next = 8; break; } _context.next = 5; return this.initialState(contextIdentifier); case 5: results = _context.sent; _context.next = 13; break; case 8: this.activeSearches.add(query); searchResponse = this.search(query, contextIdentifier); _context.next = 12; return searchResponse.mentions; case 12: results = _context.sent; case 13: this.notify(searchTime, results, query); _context.next = 19; break; case 16: _context.prev = 16; _context.t0 = _context["catch"](0); this.notifyError(_context.t0, query); case 19: case "end": return _context.stop(); } }, _callee, this, [[0, 16]]); })); function filter(_x, _x2) { return _filter.apply(this, arguments); } return filter; }() }, { key: "isFiltering", value: function isFiltering(query) { return this.activeSearches.has(query); } }, { key: "resolveMentionName", value: function resolveMentionName(id) { if (!this.config.mentionNameResolver) { return { id: id, name: '', status: MentionNameStatus.UNKNOWN }; } return this.config.mentionNameResolver.lookupName(id); } }, { key: "cacheMentionName", value: function cacheMentionName(id, mentionName) { if (!this.config.mentionNameResolver) { return; } this.config.mentionNameResolver.cacheName(id, mentionName); } }, { key: "supportsMentionNameResolving", value: function supportsMentionNameResolving() { return !!this.config.mentionNameResolver; } }, { key: "updateActiveSearches", value: function updateActiveSearches(query) { this.activeSearches.add(query); } }, { key: "verifyMentionConfig", value: function verifyMentionConfig(config) { if (!config.url) { throw new Error('config.url is a required parameter'); } if (!config.securityProvider) { config.securityProvider = emptySecurityProvider; } } }, { key: "initialState", value: function initialState(contextIdentifier) { return this.remoteInitialState(contextIdentifier); } /** * Clear a context object to generate query params by removing empty * strings, `undefined` and empty values. * * @param contextIdentifier the current context identifier * @returns a safe context for query encoding */ }, { key: "clearContext", value: function clearContext() { var contextIdentifier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return Object.keys(contextIdentifier).filter(function (key) { return contextIdentifier[key]; }).reduce(function (context, key) { return _objectSpread(_defineProperty({}, key, contextIdentifier[key]), context); }, {}); } }, { key: "getQueryParams", value: function getQueryParams(contextIdentifier) { var configParams = {}; if (this.config.containerId) { configParams['containerId'] = this.config.containerId; } if (this.config.productId) { configParams['productIdentifier'] = this.config.productId; } // if contextParams exist then it will override configParams for containerId return _objectSpread(_objectSpread({}, configParams), this.clearContext(contextIdentifier)); } /** * Returns the initial mention display list before a search is performed for the specified * container. * * @param contextIdentifier * @returns Promise */ }, { key: "remoteInitialState", value: (function () { var _remoteInitialState = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(contextIdentifier) { var queryParams, options, result; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: queryParams = this.getQueryParams(contextIdentifier); options = { path: 'bootstrap', queryParams: queryParams }; _context2.prev = 2; _context2.next = 5; return serviceUtils.requestService(this.config, options); case 5: result = _context2.sent; this._notifyAnalyticsListeners(SLI_EVENT_TYPE, SliNames.INITIAL_STATE, Actions.SUCCEEDED); return _context2.abrupt("return", this.transformServiceResponse(result, '')); case 10: _context2.prev = 10; _context2.t0 = _context2["catch"](2); this._notifyAnalyticsListeners(SLI_EVENT_TYPE, SliNames.INITIAL_STATE, Actions.FAILED); throw _context2.t0; case 14: case "end": return _context2.stop(); } }, _callee2, this, [[2, 10]]); })); function remoteInitialState(_x3) { return _remoteInitialState.apply(this, arguments); } return remoteInitialState; }()) }, { key: "search", value: function search(query, contextIdentifier) { return { mentions: this.remoteSearch(query, contextIdentifier) }; } }, { key: "remoteSearch", value: function () { var _remoteSearch = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(query, contextIdentifier) { var options, result; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: options = { path: 'search', queryParams: _objectSpread({ query: query, limit: MAX_QUERY_ITEMS }, this.getQueryParams(contextIdentifier)) }; _context3.prev = 1; _context3.next = 4; return serviceUtils.requestService(this.config, options); case 4: result = _context3.sent; this._notifyAnalyticsListeners(SLI_EVENT_TYPE, SliNames.SEARCH, Actions.SUCCEEDED); return _context3.abrupt("return", this.transformServiceResponse(result, query)); case 9: _context3.prev = 9; _context3.t0 = _context3["catch"](1); this._notifyAnalyticsListeners(SLI_EVENT_TYPE, SliNames.SEARCH, Actions.FAILED); throw _context3.t0; case 13: case "end": return _context3.stop(); } }, _callee3, this, [[1, 9]]); })); function remoteSearch(_x4, _x5) { return _remoteSearch.apply(this, arguments); } return remoteSearch; }() }, { key: "transformServiceResponse", value: function transformServiceResponse(result, query) { var mentions = result.mentions.map(function (mention) { var lozenge; if (isAppMention(mention)) { lozenge = mention.userType; } else if (isTeamMention(mention)) { lozenge = mention.userType; } return _objectSpread(_objectSpread({}, mention), {}, { lozenge: lozenge, query: query }); }); return _objectSpread(_objectSpread({}, result), {}, { mentions: mentions, query: result.query || query }); } }]); }(AbstractMentionResource); export var HttpError = /*#__PURE__*/_createClass(function HttpError(statusCode, statusMessage) { _classCallCheck(this, HttpError); this.statusCode = statusCode; this.message = statusMessage; this.name = 'HttpError'; this.stack = new Error().stack; }); export var isResolvingMentionProvider = function isResolvingMentionProvider(p) { return !!(p && p.supportsMentionNameResolving && p.supportsMentionNameResolving()); }; export { AbstractResource, AbstractMentionResource }; export default MentionResource;