UNPKG

@atlaskit/editor-plugin-collab-edit

Version:

Collab Edit plugin for @atlaskit/editor-core

338 lines (335 loc) 17.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.collabEditPlugin = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _analytics = require("@atlaskit/editor-common/analytics"); var _utils = require("@atlaskit/editor-common/utils"); var _editorJsonTransformer = require("@atlaskit/editor-json-transformer"); var _transform = require("@atlaskit/editor-prosemirror/transform"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _prosemirrorCollab = require("@atlaskit/prosemirror-collab"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _experiments = require("@atlaskit/tmp-editor-statsig/experiments"); var _analytics2 = require("./pm-plugins/analytics"); var _sendTransaction = require("./pm-plugins/events/send-transaction"); var _filterAnalytics = require("./pm-plugins/filterAnalytics"); var _main = require("./pm-plugins/main"); var _pluginKey = require("./pm-plugins/main/plugin-key"); var _mergeUnconfirmed = require("./pm-plugins/mergeUnconfirmed"); var _monitorOrganicChanges = require("./pm-plugins/monitor-organic-changes"); var _nativeCollabProviderPlugin = require("./pm-plugins/native-collab-provider-plugin"); var _trackAndFilterSpammingSteps = require("./pm-plugins/track-and-filter-spamming-steps"); var _trackLastOrganicChange = require("./pm-plugins/track-last-organic-change"); var _trackNcsInitialization = require("./pm-plugins/track-ncs-initialization"); var _trackReconnectionConflict = require("./pm-plugins/track-reconnection-conflict"); var _trackSteps = require("./pm-plugins/track-steps"); var _utils2 = require("./pm-plugins/utils"); 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; } var providerBuilder = function providerBuilder(collabEditProviderPromise) { return /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(codeToExecute, onError) { var provider; return _regenerator.default.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: _context.prev = 0; _context.next = 3; return collabEditProviderPromise; case 3: provider = _context.sent; if (!provider) { _context.next = 6; break; } return _context.abrupt("return", codeToExecute(provider)); case 6: _context.next = 11; break; case 8: _context.prev = 8; _context.t0 = _context["catch"](0); if (onError) { onError(_context.t0); } else { // eslint-disable-next-line no-console console.error(_context.t0); } case 11: case "end": return _context.stop(); } }, _callee, null, [[0, 8]]); })); return function (_x, _x2) { return _ref.apply(this, arguments); }; }(); }; var createAddInlineCommentMark = function createAddInlineCommentMark(providerPromise) { return function (_ref2) { var from = _ref2.from, to = _ref2.to, mark = _ref2.mark; providerPromise.then(function (provider) { var _provider$api; var commentMark = new _transform.AddMarkStep(Math.min(from, to), Math.max(from, to), mark); // @ts-expect-error 2339: Property 'api' does not exist on type 'CollabEditProvider<CollabEvents>'. (_provider$api = provider.api) === null || _provider$api === void 0 || _provider$api.addComment([commentMark]); }); return false; }; }; var createAddInlineCommentNodeMark = function createAddInlineCommentNodeMark(providerPromise) { return function (_ref3) { var pos = _ref3.pos, mark = _ref3.mark; providerPromise.then(function (provider) { var _provider$api2; var commentMark = new _transform.AddNodeMarkStep(pos, mark); // @ts-expect-error 2339: Property 'api' does not exist on type 'CollabEditProvider<CollabEvents>'. (_provider$api2 = provider.api) === null || _provider$api2 === void 0 || _provider$api2.addComment([commentMark]); }); return false; }; }; var collabEditPlugin = exports.collabEditPlugin = function collabEditPlugin(_ref4) { var _api$featureFlags; var options = _ref4.config, api = _ref4.api; var featureFlags = (api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState()) || {}; var providerResolver = function providerResolver() {}; var editorViewRef = { current: null }; var collabEditProviderPromise = new Promise(function (_providerResolver) { providerResolver = _providerResolver; }); var executeProviderCode = providerBuilder(collabEditProviderPromise); return { name: 'collabEdit', getSharedState: function getSharedState(state) { if (!state) { return { initialised: { collabInitialisedAt: null, firstChangeAfterInitAt: null, firstContentBodyChangeAfterInitAt: null, lastLocalOrganicChangeAt: null, lastRemoteOrganicChangeAt: null, lastLocalOrganicBodyChangeAt: null, lastRemoteOrganicBodyChangeAt: null }, activeParticipants: undefined, sessionId: undefined, lastReconnectionConflictMetadata: undefined }; } var collabPluginState = _pluginKey.pluginKey.getState(state); var metadata = _trackNcsInitialization.trackNCSInitializationPluginKey.getState(state); var lastOrganicChangeState = _trackLastOrganicChange.trackLastOrganicChangePluginKey.getState(state); var lastRemoteConflict = _trackReconnectionConflict.trackLastRemoteConflictPluginKey.getState(state); return { activeParticipants: collabPluginState === null || collabPluginState === void 0 ? void 0 : collabPluginState.activeParticipants, sessionId: collabPluginState === null || collabPluginState === void 0 ? void 0 : collabPluginState.sessionId, initialised: { collabInitialisedAt: (metadata === null || metadata === void 0 ? void 0 : metadata.collabInitialisedAt) || null, firstChangeAfterInitAt: (metadata === null || metadata === void 0 ? void 0 : metadata.firstChangeAfterInitAt) || null, firstContentBodyChangeAfterInitAt: (metadata === null || metadata === void 0 ? void 0 : metadata.firstContentBodyChangeAfterInitAt) || null, lastLocalOrganicChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastLocalOrganicChangeAt) || null, lastRemoteOrganicChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastRemoteOrganicChangeAt) || null, lastLocalOrganicBodyChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastLocalOrganicBodyChangeAt) || null, lastRemoteOrganicBodyChangeAt: (lastOrganicChangeState === null || lastOrganicChangeState === void 0 ? void 0 : lastOrganicChangeState.lastRemoteOrganicBodyChangeAt) || null }, lastReconnectionConflictMetadata: lastRemoteConflict }; }, actions: { getAvatarColor: _utils2.getAvatarColor, addInlineCommentMark: createAddInlineCommentMark(collabEditProviderPromise), addInlineCommentNodeMark: createAddInlineCommentNodeMark(collabEditProviderPromise), isRemoteReplaceDocumentTransaction: function isRemoteReplaceDocumentTransaction(tr) { return tr.getMeta('isRemote') && tr.getMeta('replaceDocument'); }, getCurrentCollabState: function getCurrentCollabState() { var _getCollabState; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var adfDocument = new _editorJsonTransformer.JSONTransformer().encode(editorViewRef.current.state.doc); return { content: adfDocument, // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion version: ((_getCollabState = (0, _prosemirrorCollab.getCollabState)(editorViewRef.current.state)) === null || _getCollabState === void 0 ? void 0 : _getCollabState.version) || 0, // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion sendableSteps: (0, _prosemirrorCollab.sendableSteps)(editorViewRef.current.state) }; }, // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any validatePMJSONDocument: function validatePMJSONDocument(doc) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any var content = (doc.content || []).map(function (child) { return ( // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion editorViewRef.current.state.schema.nodeFromJSON(child) ); }); return content.every(function (node) { try { node.check(); // this will throw an error if the node is invalid } catch (_unused) { return false; } return true; }); } }, pmPlugins: function pmPlugins() { var _ref5 = options || {}, _ref5$useNativePlugin = _ref5.useNativePlugin, useNativePlugin = _ref5$useNativePlugin === void 0 ? false : _ref5$useNativePlugin, _ref5$userId = _ref5.userId, userId = _ref5$userId === void 0 ? null : _ref5$userId; var transformUnconfirmed = function transformUnconfirmed(steps) { var transformed = steps; if ((0, _experiments.editorExperiment)('platform_editor_reduce_noisy_steps_ncs', true, { exposure: true })) { transformed = (0, _filterAnalytics.filterAnalyticsSteps)(transformed); } if ((0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true) || (0, _expValEquals.expValEquals)('platform_editor_enable_single_player_step_merging', 'isEnabled', true)) { transformed = (0, _mergeUnconfirmed.mergeUnconfirmedSteps)(transformed, api); } return transformed; }; var plugins = [].concat((0, _toConsumableArray2.default)(useNativePlugin ? [{ name: 'pmCollab', plugin: function plugin() { return (0, _prosemirrorCollab.collab)({ clientID: userId, transformUnconfirmed: transformUnconfirmed }); } }, { name: 'nativeCollabProviderPlugin', plugin: function plugin() { return (0, _nativeCollabProviderPlugin.nativeCollabProviderPlugin)({ providerPromise: collabEditProviderPromise }); } }] : []), [{ name: 'collab', plugin: function plugin(_ref6) { var dispatch = _ref6.dispatch, providerFactory = _ref6.providerFactory; return (0, _main.createPlugin)(dispatch, providerFactory, providerResolver, executeProviderCode, options, featureFlags, api); } }, { name: 'collabTrackNCSInitializationPlugin', plugin: _trackNcsInitialization.createPlugin }]); plugins.push({ name: 'trackAndFilterSpammingSteps', plugin: function plugin() { return (0, _trackAndFilterSpammingSteps.createPlugin)(function (tr) { var _api$analytics; var sanitizedSteps = tr.steps.map(function (step) { return (0, _trackAndFilterSpammingSteps.sanitizeFilteredStep)(step); }); 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({ action: _analytics.ACTION.STEPS_FILTERED, actionSubject: _analytics.ACTION_SUBJECT.COLLAB, attributes: { steps: sanitizedSteps }, eventType: _analytics.EVENT_TYPE.OPERATIONAL }); }); } }); plugins.push({ name: 'collabTrackLastOrganicChangePlugin', plugin: _trackLastOrganicChange.createPlugin }); if ((0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true)) { plugins.push({ name: 'trackLastRemoteConflictPlugin', plugin: _trackReconnectionConflict.createPlugin }); } return plugins; }, onEditorViewStateUpdated: function onEditorViewStateUpdated(props) { var _api$analytics2, _api$editorViewMode, _options$useNativePlu, _options$hideTelecurs; var addErrorAnalytics = (0, _analytics2.addSynchronyErrorAnalytics)(props.newEditorState, props.newEditorState.tr, featureFlags, api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions); var isEmptyDoc = (0, _utils.isEmptyDocument)(props.newEditorState.doc); var viewMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode; executeProviderCode((0, _sendTransaction.sendTransaction)({ originalTransaction: props.originalTransaction, transactions: props.transactions, oldEditorState: props.oldEditorState, newEditorState: props.newEditorState, useNativePlugin: (_options$useNativePlu = options.useNativePlugin) !== null && _options$useNativePlu !== void 0 ? _options$useNativePlu : false, hideTelecursorOnLoad: !isEmptyDoc && ((_options$hideTelecurs = options.hideTelecursorOnLoad) !== null && _options$hideTelecurs !== void 0 ? _options$hideTelecurs : false), viewMode: viewMode }), addErrorAnalytics); if (!(0, _expValEquals.expValEquals)('platform_editor_remove_collab_step_metrics', 'isEnabled', true)) { (0, _trackSteps.track)(_objectSpread(_objectSpread({ api: api }, props), {}, { onTrackDataProcessed: function onTrackDataProcessed(steps) { var _api$analytics3; api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.fireAnalyticsEvent({ action: _analytics.ACTION.STEPS_TRACKED, actionSubject: _analytics.ACTION_SUBJECT.COLLAB, attributes: { steps: steps }, eventType: _analytics.EVENT_TYPE.OPERATIONAL }); } })); } if ((0, _platformFeatureFlags.fg)('platform_editor_collab_organic_change_reporting')) { (0, _monitorOrganicChanges.monitorOrganic)(_objectSpread(_objectSpread({ api: api }, props), {}, { onDataProcessed: function onDataProcessed(data) { var _api$analytics4; api === null || api === void 0 || (_api$analytics4 = api.analytics) === null || _api$analytics4 === void 0 || (_api$analytics4 = _api$analytics4.actions) === null || _api$analytics4 === void 0 || _api$analytics4.fireAnalyticsEvent({ action: _analytics.ACTION.ORGANIC_CHANGES_TRACKED, actionSubject: _analytics.ACTION_SUBJECT.COLLAB, attributes: { organicChanges: data }, eventType: _analytics.EVENT_TYPE.OPERATIONAL }); } })); } }, commands: { nudgeTelepointer: function nudgeTelepointer(sessionId) { return function (_ref7) { var tr = _ref7.tr; tr.setMeta('nudgeTelepointer', { sessionId: sessionId }); return tr; }; } } }; };